changeset 7392:42b6e0905881

Merge.
author Christian Haeubl <haeubl@ssw.jku.at>
date Wed, 16 Jan 2013 09:08:24 +0100
parents 36dafe48bc38 (current diff) 6ad818b8892e (diff)
children 5f00bf5a530d
files graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/TestNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/DebugFilter.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/MethodFilter.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/IntrinsifyArrayCopyPhase.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/SystemSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSnippets.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/DoubleSnippets.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/FloatSnippets.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/IntegerSnippets.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/LongSnippets.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/MathSnippetsX86.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/NodeClassSnippets.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/UnsafeSnippets.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/UnsignedMathSnippets.java
diffstat 121 files changed, 3668 insertions(+), 2387 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java	Wed Jan 16 09:08:24 2013 +0100
@@ -25,9 +25,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 
 /**
@@ -35,29 +32,154 @@
  * and the machine code generator.
  */
 public final class ComputeBlockOrder {
-    private int blockCount;
     private List<Block> linearScanOrder;
     private List<Block> codeEmittingOrder;
-    private final BitSet visitedBlocks; // used for recursive processing of blocks
-    private final BitSet activeBlocks; // used for recursive processing of blocks
-    private final int[] forwardBranches; // number of incoming forward branches for each block
-    private final List<Block> workList; // temporary list (used in markLoops and computeOrder)
-    private final List<Block> loopHeaders;
-    private final boolean reorderLoops;
+
+    private Comparator<Block> blockComparator = new Comparator<Block>() {
+        @Override
+        public int compare(Block o1, Block o2) {
+            // Loop blocks before any loop exit block.
+            int diff = o2.getLoopDepth() - o1.getLoopDepth();
+            if (diff != 0) {
+                return diff;
+            }
+
+            // Blocks with high probability before blocks with low probability.
+            if (o1.getBeginNode().probability() > o2.getBeginNode().probability()) {
+                return -1;
+            } else {
+                return 1;
+            }
+        }};
+
+    public ComputeBlockOrder(int maxBlockId, @SuppressWarnings("unused") int loopCount, Block startBlock, @SuppressWarnings("unused") boolean reorderLoops) {
+
+        List<Block> newLinearScanOrder = new ArrayList<>();
+        List<Block> order = new ArrayList<>();
+        PriorityQueue<Block> worklist = new PriorityQueue<>(10, blockComparator);
+        BitSet orderedBlocks = new BitSet(maxBlockId);
+        orderedBlocks.set(startBlock.getId());
+        worklist.add(startBlock);
+        computeCodeEmittingOrder(order, worklist, orderedBlocks);
+        codeEmittingOrder = order;
+
+        orderedBlocks.clear();
+        orderedBlocks.set(startBlock.getId());
+        worklist.add(startBlock);
+        computeNewLinearScanOrder(newLinearScanOrder, worklist, orderedBlocks);
+
+        assert order.size() == newLinearScanOrder.size() : codeEmittingOrder.size() + " vs " + newLinearScanOrder.size();
+        linearScanOrder = newLinearScanOrder;
+    }
+
+    private void computeCodeEmittingOrder(List<Block> order, PriorityQueue<Block> worklist, BitSet orderedBlocks) {
+        while (!worklist.isEmpty()) {
+            Block nextImportantPath = worklist.poll();
+            addImportantPath(nextImportantPath, order, worklist, orderedBlocks);
+        }
+    }
+
+    private void computeNewLinearScanOrder(List<Block> order, PriorityQueue<Block> worklist, BitSet orderedBlocks) {
+        while (!worklist.isEmpty()) {
+            Block nextImportantPath = worklist.poll();
+            addImportantLinearScanOrderPath(nextImportantPath, order, worklist, orderedBlocks);
+        }
+    }
+
+    private void addImportantLinearScanOrderPath(Block block, List<Block> order, PriorityQueue<Block> worklist, BitSet orderedBlocks) {
+        order.add(block);
+
+        Block bestSucc = null;
+        double bestSuccProb = 0;
+
+        for (Block succ : block.getSuccessors()) {
+            if (!orderedBlocks.get(succ.getId()) && succ.getLoopDepth() >= block.getLoopDepth()) {
+                double curProb = succ.getBeginNode().probability();
+                if (curProb >= bestSuccProb) {
+                    bestSuccProb = curProb;
+                    bestSucc = succ;
+                }
+                assert curProb >= 0 : curProb;
+            }
+        }
 
-    public ComputeBlockOrder(int maxBlockId, int loopCount, Block startBlock, boolean reorderLoops) {
-        loopHeaders = new ArrayList<>(loopCount);
-        while (loopHeaders.size() < loopCount) {
-            loopHeaders.add(null);
+        for (Block succ : block.getSuccessors()) {
+            if (!orderedBlocks.get(succ.getId())) {
+                if (succ != bestSucc) {
+                    orderedBlocks.set(succ.getId());
+                    worklist.add(succ);
+                }
+            }
+        }
+
+        if (bestSucc != null) {
+            if (!bestSucc.isLoopHeader() && bestSucc.getPredecessors().size() > 1) {
+                // We are at a merge. Check probabilities of predecessors that are not yet scheduled.
+                double unscheduledSum = 0.0;
+                double scheduledSum = 0.0;
+                for (Block pred : bestSucc.getPredecessors()) {
+                    if (!orderedBlocks.get(pred.getId())) {
+                        unscheduledSum += pred.getBeginNode().probability();
+                    } else {
+                        scheduledSum += pred.getBeginNode().probability();
+                    }
+                }
+
+                if (unscheduledSum > 0.0 && unscheduledSum > scheduledSum / 10) {
+                    return;
+                }
+            }
+            orderedBlocks.set(bestSucc.getId());
+            addImportantLinearScanOrderPath(bestSucc, order, worklist, orderedBlocks);
+        }
+    }
+
+    private void addImportantPath(Block block, List<Block> order, PriorityQueue<Block> worklist, BitSet orderedBlocks) {
+        if (!skipLoopHeader(block)) {
+            if (block.isLoopHeader()) {
+                block.align = true;
+            }
+            order.add(block);
         }
-        visitedBlocks = new BitSet(maxBlockId);
-        activeBlocks = new BitSet(maxBlockId);
-        forwardBranches = new int[maxBlockId];
-        workList = new ArrayList<>(8);
-        this.reorderLoops = reorderLoops;
+        if (block.isLoopEnd() && skipLoopHeader(block.getLoop().header)) {
+            order.add(block.getLoop().header);
+            for (Block succ : block.getLoop().header.getSuccessors()) {
+                if (succ.getLoopDepth() == block.getLoopDepth()) {
+                    succ.align = true;
+                }
+            }
+        }
+        Block bestSucc = null;
+        double bestSuccProb = 0;
 
-        countEdges(startBlock, null);
-        computeOrder(startBlock);
+        for (Block succ : block.getSuccessors()) {
+            if (!orderedBlocks.get(succ.getId()) && succ.getLoopDepth() >= block.getLoopDepth()) {
+                double curProb = succ.getBeginNode().probability();
+                if (curProb >= bestSuccProb) {
+                    bestSuccProb = curProb;
+                    bestSucc = succ;
+                }
+                assert curProb >= 0 : curProb;
+            }
+        }
+
+        for (Block succ : block.getSuccessors()) {
+            if (!orderedBlocks.get(succ.getId())) {
+                if (succ != bestSucc) {
+                    orderedBlocks.set(succ.getId());
+                    worklist.add(succ);
+                }
+            }
+        }
+
+        if (bestSucc != null) {
+            orderedBlocks.set(bestSucc.getId());
+            addImportantPath(bestSucc, order, worklist, orderedBlocks);
+        }
+    }
+
+    private static boolean skipLoopHeader(Block bestSucc) {
+        return (bestSucc.isLoopHeader() && !bestSucc.isLoopEnd() && bestSucc.getLoop().loopBegin().loopEnds().count() == 1);
     }
 
     /**
@@ -75,209 +197,4 @@
     public List<Block> codeEmittingOrder() {
         return codeEmittingOrder;
     }
-
-    private boolean isVisited(Block b) {
-        return visitedBlocks.get(b.getId());
-    }
-
-    private boolean isActive(Block b) {
-        return activeBlocks.get(b.getId());
-    }
-
-    private void setVisited(Block b) {
-        assert !isVisited(b);
-        visitedBlocks.set(b.getId());
-    }
-
-    private void setActive(Block b) {
-        assert !isActive(b);
-        activeBlocks.set(b.getId());
-    }
-
-    private void clearActive(Block b) {
-        assert isActive(b);
-        activeBlocks.clear(b.getId());
-    }
-
-    private void incForwardBranches(Block b) {
-        forwardBranches[b.getId()]++;
-    }
-
-    private int decForwardBranches(Block b) {
-        return --forwardBranches[b.getId()];
-    }
-
-    /**
-     * Traverses the CFG to analyze block and edge info. The analysis performed is:
-     *
-     * 1. Count of total number of blocks.
-     * 2. Count of all incoming edges and backward incoming edges.
-     * 3. Number loop header blocks.
-     * 4. Create a list with all loop end blocks.
-     */
-    private void countEdges(Block cur, Block parent) {
-        Debug.log("Counting edges for block B%d%s", cur.getId(), parent == null ? "" : " coming from B" + parent.getId());
-
-        if (isActive(cur)) {
-            return;
-        }
-
-        // increment number of incoming forward branches
-        incForwardBranches(cur);
-
-        if (isVisited(cur)) {
-            return;
-        }
-
-        blockCount++;
-        setVisited(cur);
-        setActive(cur);
-
-        // recursive call for all successors
-        for (int i = cur.numberOfSux() - 1; i >= 0; i--) {
-            countEdges(cur.suxAt(i), cur);
-        }
-
-        clearActive(cur);
-
-        Debug.log("Finished counting edges for block B%d", cur.getId());
-    }
-
-    private static int computeWeight(Block cur) {
-
-        // limit loop-depth to 15 bit (only for security reason, it will never be so big)
-        int weight = (cur.getLoopDepth() & 0x7FFF) << 16;
-
-        int curBit = 15;
-
-        // loop end blocks (blocks that end with a backward branch) are added
-        // after all other blocks of the loop.
-        if (!cur.isLoopEnd()) {
-            weight |= 1 << curBit;
-        }
-        curBit--;
-
-        // exceptions handlers are added as late as possible
-        if (!cur.isExceptionEntry()) {
-            weight |= 1 << curBit;
-        }
-        curBit--;
-
-        // guarantee that weight is > 0
-        weight |= 1;
-
-        assert curBit >= 0 : "too many flags";
-        assert weight > 0 : "weight cannot become negative";
-
-        return weight;
-    }
-
-    private boolean readyForProcessing(Block cur) {
-        // Discount the edge just traveled.
-        // When the number drops to zero, all forward branches were processed
-        if (decForwardBranches(cur) != 0) {
-            return false;
-        }
-
-        assert !linearScanOrder.contains(cur) : "block already processed (block can be ready only once)";
-        assert !workList.contains(cur) : "block already in work-list (block can be ready only once)";
-        return true;
-    }
-
-    private void sortIntoWorkList(Block cur) {
-        assert !workList.contains(cur) : "block already in work list";
-
-        int curWeight = computeWeight(cur);
-
-        // the linearScanNumber is used to cache the weight of a block
-        cur.linearScanNumber = curWeight;
-
-        workList.add(null); // provide space for new element
-
-        int insertIdx = workList.size() - 1;
-        while (insertIdx > 0 && workList.get(insertIdx - 1).linearScanNumber > curWeight) {
-            workList.set(insertIdx, workList.get(insertIdx - 1));
-            insertIdx--;
-        }
-        workList.set(insertIdx, cur);
-
-        if (Debug.isLogEnabled()) {
-            Debug.log("Sorted B%d into worklist. new worklist:", cur.getId());
-            for (int i = 0; i < workList.size(); i++) {
-                Debug.log(String.format("%8d B%02d  weight:%6x", i, workList.get(i).getId(), workList.get(i).linearScanNumber));
-            }
-        }
-
-        for (int i = 0; i < workList.size(); i++) {
-            assert workList.get(i).linearScanNumber > 0 : "weight not set";
-            assert i == 0 || workList.get(i - 1).linearScanNumber <= workList.get(i).linearScanNumber : "incorrect order in worklist";
-        }
-    }
-
-    private void appendBlock(Block cur) {
-        Debug.log("appending block B%d (weight 0x%06x) to linear-scan order", cur.getId(), cur.linearScanNumber);
-        assert !linearScanOrder.contains(cur) : "cannot add the same block twice";
-
-        cur.linearScanNumber = linearScanOrder.size();
-        linearScanOrder.add(cur);
-
-        if (cur.isLoopEnd() && cur.isLoopHeader()) {
-            codeEmittingOrder.add(cur);
-        } else {
-            if (!cur.isLoopHeader() || ((LoopBeginNode) cur.getBeginNode()).loopEnds().count() > 1 || !reorderLoops) {
-                codeEmittingOrder.add(cur);
-
-                if (cur.isLoopEnd() && reorderLoops) {
-                    Block loopHeader = loopHeaders.get(cur.getLoop().index);
-                    if (loopHeader != null) {
-                        codeEmittingOrder.add(loopHeader);
-
-                        for (int i = 0; i < loopHeader.numberOfSux(); i++) {
-                            Block succ = loopHeader.suxAt(i);
-                            if (succ.getLoopDepth() == loopHeader.getLoopDepth()) {
-                                succ.align = true;
-                            }
-                        }
-                    }
-                }
-            } else {
-                loopHeaders.set(cur.getLoop().index, cur);
-            }
-        }
-    }
-
-    private void checkAndSortIntoWorkList(Block b) {
-        if (readyForProcessing(b)) {
-            sortIntoWorkList(b);
-        }
-    }
-
-    private void computeOrder(Block startBlock) {
-        // the start block is always the first block in the linear scan order
-        linearScanOrder = new ArrayList<>(blockCount);
-
-        codeEmittingOrder = new ArrayList<>(blockCount);
-
-        // start processing with standard entry block
-        assert workList.isEmpty() : "list must be empty before processing";
-
-        assert readyForProcessing(startBlock);
-        sortIntoWorkList(startBlock);
-
-        do {
-            Block cur = workList.remove(workList.size() - 1);
-            appendBlock(cur);
-
-            Node endNode = cur.getEndNode();
-            if (endNode instanceof IfNode && ((IfNode) endNode).probability() < 0.5) {
-                assert cur.numberOfSux() == 2;
-                checkAndSortIntoWorkList(cur.suxAt(1));
-                checkAndSortIntoWorkList(cur.suxAt(0));
-            } else {
-                for (Block sux : cur.getSuccessors()) {
-                    checkAndSortIntoWorkList(sux);
-                }
-            }
-        } while (workList.size() > 0);
-    }
 }
--- /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	Wed Jan 16 09:08:24 2013 +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/MetaAccessProvider.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java	Wed Jan 16 09:08:24 2013 +0100
@@ -60,6 +60,13 @@
     ResolvedJavaType lookupJavaType(Constant constant);
 
     /**
+     * Parses a <a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3">method
+     * descriptor</a> into a {@link Signature}. The behavior of this method is undefined if
+     * the method descriptor is not well formed.
+     */
+    Signature parseMethodDescriptor(String methodDescriptor);
+
+    /**
      * Compares two constants for equality.
      * This is used instead of {@link Constant#equals(Object)} in case the runtime
      * has an interpretation for object equality other than {@code x.asObject() == y.asObject()}.
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java	Wed Jan 16 09:08:24 2013 +0100
@@ -494,23 +494,6 @@
     }
 
     /**
-     * Converts a {@link Signature} to internal representation, i.e., the signature
-     * <pre>(int, String, double)void</pre> is converted to <pre>(ILjava/lang/String;D)V</pre>.
-     *
-     * @param sig the {@link Signature} to be converted.
-     *
-     * @return the signature's internal representation as a string.
-     */
-    public static String signatureToInternal(Signature sig) {
-        StringBuilder sb = new StringBuilder("(");
-        for (int i = 0; i < sig.getParameterCount(false); ++i) {
-            sb.append(sig.getParameterType(i, null).getName());
-        }
-        sb.append(')').append(sig.getReturnType(null).getName());
-        return sb.toString();
-    }
-
-    /**
      * Formats some profiling information associated as a string.
      *
      * @param info the profiling info to format
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Wed Jan 16 09:08:24 2013 +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	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Wed Jan 16 09:08:24 2013 +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.api.meta/src/com/oracle/graal/api/meta/Signature.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Signature.java	Wed Jan 16 09:08:24 2013 +0100
@@ -24,14 +24,14 @@
 
 /**
  * Represents a method signature provided by the runtime.
- * 
- * @see <a href="http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#7035">Method Descriptors</a>
+ *
+ * @see <a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3">Method Descriptors</a>
  */
 public interface Signature {
 
     /**
      * Returns the number of parameters in this signature, adding 1 for a receiver if requested.
-     * 
+     *
      * @param receiver true if 1 is to be added to the result for a receiver
      * @return the number of parameters; + 1 iff {@code receiver == true}
      */
@@ -40,7 +40,7 @@
     /**
      * Gets the parameter type at the specified position. This method returns a {@linkplain ResolvedJavaType resolved}
      * type if possible but without triggering any class loading or resolution.
-     * 
+     *
      * @param index the index into the parameters, with {@code 0} indicating the first parameter
      * @param accessingClass the context of the type lookup. If accessing class is provided, its class loader is used to
      *            retrieve an existing resolved type. This value can be {@code null} if the caller does not care for a
@@ -52,7 +52,7 @@
     /**
      * Gets the parameter kind at the specified position. This is the same as calling {@link #getParameterType}.
      * {@link JavaType#getKind getKind}.
-     * 
+     *
      * @param index the index into the parameters, with {@code 0} indicating the first parameter
      * @return the kind of the parameter at the specified position
      */
@@ -61,7 +61,7 @@
     /**
      * Gets the return type of this signature. This method will return a {@linkplain ResolvedJavaType resolved} type if
      * possible but without triggering any class loading or resolution.
-     * 
+     *
      * @param accessingClass the context of the type lookup. If accessing class is provided, its class loader is used to
      *            retrieve an existing resolved type. This value can be {@code null} if the caller does not care for a
      *            resolved type.
@@ -77,10 +77,21 @@
 
     /**
      * Gets the size, in Java slots, of the parameters to this signature.
-     * 
+     *
      * @param withReceiver {@code true} if to add a slot for a receiver object; {@code false} not to include the
      *            receiver
      * @return the size of the parameters in slots
      */
     int getParameterSlots(boolean withReceiver);
+
+    /**
+     * Gets the <a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3">method
+     * descriptor</a> corresponding to this signature.
+     * For example:
+     *
+     * <pre>(ILjava/lang/String;D)V</pre>.
+     *
+     * @return the signature as a string
+     */
+    String getMethodDescriptor();
 }
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Wed Jan 16 09:08:24 2013 +0100
@@ -40,7 +40,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
-import com.oracle.graal.lir.StandardOp.LabelOp;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivOp;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.Op1Reg;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.Op1Stack;
@@ -221,11 +220,6 @@
     }
 
     @Override
-    public void emitLabel(Label label, boolean align) {
-        append(new LabelOp(label, align));
-    }
-
-    @Override
     public void emitJump(LabelRef label, LIRFrameState info) {
         append(new JumpOp(label, info));
     }
@@ -346,7 +340,49 @@
     }
 
     @Override
-    public Variable emitDiv(Value a, Value b) {
+    protected boolean peephole(ValueNode valueNode) {
+        if ((valueNode instanceof IntegerDivNode) || (valueNode instanceof IntegerRemNode)) {
+            FixedBinaryNode divRem = (FixedBinaryNode) valueNode;
+            FixedNode node = divRem.next();
+            while (node instanceof FixedWithNextNode) {
+                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
+                if (((fixedWithNextNode instanceof IntegerDivNode) || (fixedWithNextNode instanceof IntegerRemNode)) && fixedWithNextNode.getClass() != divRem.getClass()) {
+                    FixedBinaryNode otherDivRem = (FixedBinaryNode) fixedWithNextNode;
+                    if (otherDivRem.x() == divRem.x() && otherDivRem.y() == divRem.y() && operand(otherDivRem) == null) {
+                        Value[] results = emitIntegerDivRem(operand(divRem.x()), operand(divRem.y()));
+                        if (divRem instanceof IntegerDivNode) {
+                            setResult(divRem, results[0]);
+                            setResult(otherDivRem, results[1]);
+                        } else {
+                            setResult(divRem, results[1]);
+                            setResult(otherDivRem, results[0]);
+                        }
+                        return true;
+                    }
+                }
+                node = fixedWithNextNode.next();
+            }
+        }
+        return false;
+    }
+
+    public Value[] emitIntegerDivRem(Value a, Value b) {
+        switch(a.getKind()) {
+            case Int:
+                emitMove(a, RAX_I);
+                append(new DivRemOp(IDIVREM, RAX_I, load(b), state()));
+                return new Value[]{emitMove(RAX_I), emitMove(RDX_I)};
+            case Long:
+                emitMove(a, RAX_L);
+                append(new DivRemOp(LDIVREM, RAX_L, load(b), state()));
+                return new Value[]{emitMove(RAX_L), emitMove(RDX_L)};
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Value emitDiv(Value a, Value b) {
         switch(a.getKind()) {
             case Int:
                 emitMove(a, RAX_I);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Wed Jan 16 09:08:24 2013 +0100
@@ -42,6 +42,7 @@
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.PhasePlan.PhasePosition;
 import com.oracle.graal.phases.schedule.*;
+import com.oracle.graal.printer.*;
 
 /**
  * Base class for Graal compiler unit tests.
@@ -68,7 +69,7 @@
     protected final GraalCompiler graalCompiler;
 
     public GraalCompilerTest() {
-        Debug.enable();
+        DebugEnvironment.initialize(System.out);
         this.runtime = Graal.getRequiredCapability(GraalCodeCacheProvider.class);
         this.graalCompiler = Graal.getRequiredCapability(GraalCompiler.class);
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java	Wed Jan 16 09:08:24 2013 +0100
@@ -97,6 +97,7 @@
                 Debug.dump(graph, "Graph");
                 new ExpandBoxingNodesPhase(pool).apply(graph);
                 new CanonicalizerPhase(null, runtime(), assumptions).apply(graph);
+                new CanonicalizerPhase(null, runtime(), assumptions).apply(graph);
                 new DeadCodeEliminationPhase().apply(graph);
                 StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET);
                 new CanonicalizerPhase(null, runtime(), assumptions).apply(referenceGraph);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/DebugFilter.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2012, 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.compiler;
+
+import java.util.*;
+import java.util.regex.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.internal.*;
+import com.oracle.graal.phases.*;
+
+/**
+ * Implements the filter specified by the {@link GraalOptions#Dump},
+ * {@link GraalOptions#Log}, {@link GraalOptions#Meter} and {@link GraalOptions#Time}
+ * options.
+ * <p>
+ * These options enable the associated debug facility if their filter
+ * matches the {@linkplain DebugScope#getQualifiedName() name} of the
+ * {@linkplain Debug#currentScope() current scope}.
+ * <p>
+ * A filter is a list of comma-separated terms. Each term is interpreted
+ * as a glob pattern if it contains a "*" or "?" character. Otherwise, it is
+ * interpreted as a substring. If a term starts with "~", then it is an
+ * positive term. An input is matched by a filter if any of its positive
+ * terms match the input (or it has no positive terms) AND none of its
+ * negative terms match the input (or it has no negative terms).
+ * <p>
+ * Examples of filters include:
+ * <p>
+ * <ul>
+ * <li><pre>""</pre>
+ * Matches any scope.</li>
+ * <li><pre>"*"</pre>
+ * Matches any scope.</li>
+ * <li><pre>"CodeGen,CodeInstall"</pre>
+ * Matches a scope whose name contains "CodeGen" or "CodeInstall".</li>
+ * <li><pre>"Code*"</pre>
+ * Matches a scope whose name starts with "Code".</li>
+ * <li><pre>"Code,~Dead"</pre>
+ * Matches a scope whose name contains "Code" but does not contain "Dead".</li>
+ * </ul>
+ */
+class DebugFilter {
+
+    public static DebugFilter parse(String spec) {
+        if (spec == null) {
+            return null;
+        }
+        return new DebugFilter(spec.split(","));
+    }
+
+    final Term[] positive;
+    final Term[] negative;
+
+    DebugFilter(String[] terms) {
+        List<Term> pos = new ArrayList<>(terms.length);
+        List<Term> neg = new ArrayList<>(terms.length);
+        for (int i = 0; i < terms.length; i++) {
+            String t = terms[i];
+            if (t.startsWith("~")) {
+                neg.add(new Term(t.substring(1)));
+            } else {
+                pos.add(new Term(t));
+            }
+        }
+        this.positive = pos.isEmpty() ? null : pos.toArray(new Term[pos.size()]);
+        this.negative = neg.isEmpty() ? null : neg.toArray(new Term[neg.size()]);
+    }
+
+    /**
+     * Determines if a given input is matched by this filter.
+     */
+    public boolean matches(String input) {
+        boolean match = true;
+        if (positive != null) {
+            match = false;
+            for (Term t : positive) {
+                if (t.matches(input)) {
+                    match = true;
+                    break;
+                }
+            }
+        }
+        if (match && negative != null) {
+            for (Term t : negative) {
+                if (t.matches(input)) {
+                    match = false;
+                    break;
+                }
+            }
+        }
+//        if (match) {
+//            System.out.println(this + " matches " + input);
+//        }
+        return match;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder("DebugFilter[");
+        String sep = "";
+        if (positive != null) {
+            buf.append(sep).append("pos=").append(Arrays.toString(positive));
+            sep = ", ";
+        }
+        if (negative != null) {
+            buf.append(sep).append("neg=").append(Arrays.toString(negative));
+            sep = ", ";
+        }
+        return buf.append("]").toString();
+    }
+
+    static class Term {
+
+        final Pattern pattern;
+
+        public Term(String filter) {
+            if (filter.isEmpty()) {
+                this.pattern = null;
+            } else if (filter.contains("*") || filter.contains("?")) {
+                this.pattern = Pattern.compile(MethodFilter.createGlobString(filter));
+            } else {
+                this.pattern = Pattern.compile(".*" + MethodFilter.createGlobString(filter) + ".*");
+            }
+        }
+
+        /**
+         * Determines if a given input is matched by this filter.
+         */
+        public boolean matches(String input) {
+            return pattern == null || pattern.matcher(input).matches();
+        }
+
+        @Override
+        public String toString() {
+            return pattern == null ? ".*" : pattern.toString();
+        }
+    }
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed Jan 16 09:08:24 2013 +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);
             }
@@ -209,6 +209,8 @@
         assert startBlock != null;
         assert startBlock.numberOfPreds() == 0;
 
+        new ComputeProbabilityPhase().apply(graph);
+
         return Debug.scope("ComputeLinearScanOrder", new Callable<LIR>() {
 
             @Override
@@ -228,6 +230,7 @@
 
             }
         });
+
     }
 
     public FrameMap emitLIR(final LIR lir, StructuredGraph graph, final ResolvedJavaMethod method) {
@@ -238,11 +241,22 @@
 
             public void run() {
                 for (Block b : lir.linearScanOrder()) {
-                    lirGenerator.doBlock(b);
+                    emitBlock(b);
                 }
 
                 Debug.dump(lir, "After LIR generation");
             }
+
+            private void emitBlock(Block b) {
+                if (lir.lir(b) == null) {
+                    for (Block pred : b.getPredecessors()) {
+                        if (!b.isLoopHeader() || !pred.isLoopEnd()) {
+                            emitBlock(pred);
+                        }
+                    }
+                    lirGenerator.doBlock(b);
+                }
+            }
         });
 
         Debug.scope("Allocator", new Runnable() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2012, 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.compiler;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.*;
+
+public class GraalDebugConfig implements DebugConfig {
+
+    private final DebugFilter logFilter;
+    private final DebugFilter meterFilter;
+    private final DebugFilter timerFilter;
+    private final DebugFilter dumpFilter;
+    private final MethodFilter[] methodFilter;
+    private final List<DebugDumpHandler> dumpHandlers;
+    private final PrintStream output;
+    private final Set<Object> extraFilters = new HashSet<>();
+
+    public GraalDebugConfig(String logFilter, String meterFilter, String timerFilter, String dumpFilter, String methodFilter, PrintStream output, List<DebugDumpHandler> dumpHandlers) {
+        this.logFilter = DebugFilter.parse(logFilter);
+        this.meterFilter = DebugFilter.parse(meterFilter);
+        this.timerFilter = DebugFilter.parse(timerFilter);
+        this.dumpFilter = DebugFilter.parse(dumpFilter);
+        if (methodFilter == null || methodFilter.isEmpty()) {
+            this.methodFilter = null;
+        } else {
+            String[] filters = methodFilter.split(",");
+            this.methodFilter = new MethodFilter[filters.length];
+            for (int i = 0; i < filters.length; i++) {
+                this.methodFilter[i] = new MethodFilter(filters[i]);
+            }
+        }
+
+        // Report the filters that have been configured so the user can verify it's what they expect
+        if (logFilter != null || meterFilter != null || timerFilter != null || dumpFilter != null || methodFilter != null) {
+            TTY.println(Thread.currentThread().getName() + ": " + toString());
+        }
+        this.dumpHandlers = dumpHandlers;
+        this.output = output;
+    }
+
+    public boolean isLogEnabled() {
+        return isEnabled(logFilter);
+    }
+
+    public boolean isMeterEnabled() {
+        return isEnabled(meterFilter);
+    }
+
+    public boolean isDumpEnabled() {
+        return isEnabled(dumpFilter);
+    }
+
+    public boolean isTimeEnabled() {
+        return isEnabled(timerFilter);
+    }
+
+    public PrintStream output() {
+        return output;
+    }
+
+    private boolean isEnabled(DebugFilter filter) {
+        return checkDebugFilter(Debug.currentScope(), filter) && checkMethodFilter();
+    }
+
+    private static boolean checkDebugFilter(String currentScope, DebugFilter filter) {
+        return filter != null && filter.matches(currentScope);
+    }
+
+    private boolean checkMethodFilter() {
+        if (methodFilter == null && extraFilters.isEmpty()) {
+            return true;
+        } else {
+            for (Object o : Debug.context()) {
+                if (extraFilters.contains(o)) {
+                    return true;
+                } else if (methodFilter != null) {
+                    if (o instanceof JavaMethod) {
+                        for (MethodFilter filter : methodFilter) {
+                            if (filter.matches((JavaMethod) o)) {
+                                return true;
+                            }
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Debug config:");
+        add(sb, "Log", logFilter);
+        add(sb, "Meter", meterFilter);
+        add(sb, "Time", timerFilter);
+        add(sb, "Dump", dumpFilter);
+        add(sb, "MethodFilter", methodFilter);
+        return sb.toString();
+    }
+
+    private static void add(StringBuilder sb, String name, Object filter) {
+        if (filter != null) {
+            sb.append(' ');
+            sb.append(name);
+            sb.append('=');
+            if (filter instanceof Object[]) {
+                sb.append(Arrays.toString((Object[]) filter));
+            } else {
+                sb.append(String.valueOf(filter));
+            }
+        }
+    }
+
+    @Override
+    public RuntimeException interceptException(Throwable e) {
+        if (e instanceof BailoutException) {
+            return null;
+        }
+        Debug.setConfig(Debug.fixedConfig(true, true, false, false, dumpHandlers, output));
+        Debug.log(String.format("Exception occurred in scope: %s", Debug.currentScope()));
+        for (Object o : Debug.context()) {
+            if (o instanceof Graph) {
+                Debug.log("Context obj %s", o);
+                if (GraalOptions.DumpOnError) {
+                    Debug.dump(o, "Exception graph");
+                } else {
+                    Debug.log("Use -G:+DumpOnError to enable dumping of graphs on this error");
+                }
+            } else if (o instanceof Node) {
+                String location = GraphUtil.approxSourceLocation((Node) o);
+                if (location != null) {
+                    Debug.log("Context obj %s (approx. location: %s)", o, location);
+                } else {
+                    Debug.log("Context obj %s", o);
+                }
+            } else {
+                Debug.log("Context obj %s", o);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Collection<DebugDumpHandler> dumpHandlers() {
+        return dumpHandlers;
+    }
+
+    @Override
+    public void addToContext(Object o) {
+        extraFilters.add(o);
+    }
+
+    @Override
+    public void removeFromContext(Object o) {
+        extraFilters.remove(o);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/MethodFilter.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2012, 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.compiler;
+
+import java.util.*;
+import java.util.regex.*;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * This class implements a method filter that can filter based on class name, method name and parameters.
+ * The syntax for the source pattern that is passed to the constructor is as follows:
+ *
+ * <pre>
+ * SourcePattern = [ Class "." ] method [ "(" [ Parameter { ";" Parameter } ] ")" ] .
+ * Parameter = Class | "int" | "long" | "float" | "double" | "short" | "char" | "boolean" .
+ * Class = { package "." } class .
+ * </pre>
+ *
+ *
+ * Glob pattern matching (*, ?) is allowed in all parts of the source pattern. Examples for valid filters are:
+ *
+ * <ul>
+ * <li><pre>visit(Argument;BlockScope)</pre>
+ * Matches all methods named "visit", with the first parameter of type "Argument", and the second parameter of type "BlockScope".
+ * The packages of the parameter types are irrelevant.</li>
+ * <li><pre>arraycopy(Object;;;;)</pre>
+ * Matches all methods named "arraycopy", with the first parameter of type "Object", and four more parameters of any type.
+ * The packages of the parameter types are irrelevant.</li>
+ * <li><pre>com.oracle.graal.compiler.graph.PostOrderNodeIterator.*</pre>
+ * Matches all methods in the class "com.oracle.graal.compiler.graph.PostOrderNodeIterator".</li>
+ * <li><pre>*</pre>
+ * Matches all methods in all classes</li>
+ * <li><pre>com.oracle.graal.compiler.graph.*.visit</pre>
+ * Matches all methods named "visit" in classes in the package "com.oracle.graal.compiler.graph".</pre>
+ * </ul>
+ */
+public class MethodFilter {
+
+    private final Pattern clazz;
+    private final Pattern methodName;
+    private final Pattern[] signature;
+
+    public MethodFilter(String sourcePattern) {
+        String pattern = sourcePattern.trim();
+
+        // extract parameter part
+        int pos = pattern.indexOf('(');
+        if (pos != -1) {
+            if (pattern.charAt(pattern.length() - 1) != ')') {
+                throw new IllegalArgumentException("missing ')' at end of method filter pattern: " + pattern);
+            }
+            String[] signatureClasses = pattern.substring(pos + 1, pattern.length() - 1).split(";", -1);
+            signature = new Pattern[signatureClasses.length];
+            for (int i = 0; i < signatureClasses.length; i++) {
+                signature[i] = createClassGlobPattern(signatureClasses[i].trim());
+            }
+            pattern = pattern.substring(0, pos);
+        } else {
+            signature = null;
+        }
+
+        // If there is at least one "." then everything before the last "." is the class name.
+        // Otherwise, the pattern contains only the method name.
+        pos = pattern.lastIndexOf('.');
+        if (pos != -1) {
+            clazz = createClassGlobPattern(pattern.substring(0, pos));
+            methodName = Pattern.compile(createGlobString(pattern.substring(pos + 1)));
+        } else {
+            clazz = null;
+            methodName = Pattern.compile(createGlobString(pattern));
+        }
+    }
+
+    static String createGlobString(String pattern) {
+        return Pattern.quote(pattern).replace("?", "\\E.\\Q").replace("*", "\\E.*\\Q");
+    }
+
+    private static Pattern createClassGlobPattern(String pattern) {
+        if (pattern.length() == 0) {
+            return null;
+        } else if (pattern.contains(".")) {
+            return Pattern.compile(createGlobString(pattern));
+        } else {
+            return Pattern.compile("([^\\.]*\\.)*" + createGlobString(pattern));
+        }
+    }
+
+    public boolean matches(JavaMethod o) {
+        // check method name first, since MetaUtil.toJavaName is expensive
+        if (methodName != null && !methodName.matcher(o.getName()).matches()) {
+            return false;
+        }
+        if (clazz != null && !clazz.matcher(MetaUtil.toJavaName(o.getDeclaringClass())).matches()) {
+            return false;
+        }
+        if (signature != null) {
+            Signature sig = o.getSignature();
+            if (sig.getParameterCount(false) != signature.length) {
+                return false;
+            }
+            for (int i = 0; i < signature.length; i++) {
+                JavaType type = sig.getParameterType(i, null);
+                String javaName = MetaUtil.toJavaName(type);
+                if (signature[i] != null && !signature[i].matcher(javaName).matches()) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder("MethodFilter[");
+        String sep = "";
+        if (clazz != null) {
+            buf.append(sep).append("clazz=").append(clazz);
+            sep = ", ";
+        }
+        if (methodName != null) {
+            buf.append(sep).append("methodName=").append(methodName);
+            sep = ", ";
+        }
+        if (signature != null) {
+            buf.append(sep).append("signature=").append(Arrays.toString(signature));
+            sep = ", ";
+        }
+        return buf.append("]").toString();
+    }
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Wed Jan 16 09:08:24 2013 +0100
@@ -373,12 +373,20 @@
                 stateAfter = ((StateSplit) instr).stateAfter();
             }
             if (instr instanceof ValueNode) {
-                try {
-                    doRoot((ValueNode) instr);
-                } catch (GraalInternalError e) {
-                    throw e.addContext(instr);
-                } catch (Throwable e) {
-                    throw new GraalInternalError(e).addContext(instr);
+
+                ValueNode valueNode = (ValueNode) instr;
+                if (operand(valueNode) == null) {
+                    if (!peephole(valueNode)) {
+                        try {
+                            doRoot((ValueNode) instr);
+                        } catch (GraalInternalError e) {
+                            throw e.addContext(instr);
+                        } catch (Throwable e) {
+                            throw new GraalInternalError(e).addContext(instr);
+                        }
+                    }
+                } else {
+                    // There can be cases in which the result of an instruction is already set before by other instructions.
                 }
             }
             if (stateAfter != null) {
@@ -416,6 +424,8 @@
         }
     }
 
+    protected abstract boolean peephole(ValueNode valueNode);
+
     private boolean checkStateReady(FrameState state) {
         FrameState fs = state;
         while (fs != null) {
@@ -670,7 +680,6 @@
     }
 
 
-    public abstract void emitLabel(Label label, boolean align);
     public abstract void emitJump(LabelRef label, LIRFrameState info);
     public abstract void emitBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef label, LIRFrameState info);
     public abstract Variable emitCMove(Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue);
--- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/TestNode.java	Wed Jan 16 09:05:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * 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.graph;
-
-
-public class TestNode extends Node implements Node.IterableNodeType {
-    private String name;
-
-    public TestNode(String name) {
-        this.name = name;
-    }
-
-
-    public String getName() {
-        return name;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/TestNodeInterface.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,28 @@
+/*
+ * 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.graph;
+
+
+public interface TestNodeInterface {
+    String getName();
+}
--- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/TypedNodeIteratorTest.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/TypedNodeIteratorTest.java	Wed Jan 16 09:08:24 2013 +0100
@@ -31,6 +31,16 @@
 
 public class TypedNodeIteratorTest {
 
+    private static class TestNode extends Node implements Node.IterableNodeType, TestNodeInterface {
+        private final String name;
+        public TestNode(String name) {
+            this.name = name;
+        }
+        public String getName() {
+            return name;
+        }
+    }
+
     @Test
     public void singleNodeTest() {
         Graph graph = new Graph();
@@ -144,9 +154,9 @@
         assertEquals(3, z);
     }
 
-    private static String toString(Iterable<TestNode> nodes) {
+    public static String toString(Iterable<? extends TestNodeInterface> nodes) {
         StringBuilder sb = new StringBuilder();
-        for (TestNode tn : nodes) {
+        for (TestNodeInterface tn : nodes) {
             sb.append(tn.getName());
         }
         return sb.toString();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/TypedNodeIteratorTest2.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,93 @@
+/*
+ * 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.graph;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+
+public class TypedNodeIteratorTest2 {
+
+    private static class NodeA extends Node implements TestNodeInterface {
+        private final String name;
+        public NodeA(String name) {
+            this.name = name;
+        }
+        public String getName() {
+            return name;
+        }
+    }
+
+    private static class NodeB extends NodeA implements Node.IterableNodeType {
+        public NodeB(String name) {
+            super(name);
+        }
+    }
+
+    private static class NodeC extends NodeB {
+        public NodeC(String name) {
+            super(name);
+        }
+    }
+
+    private static class NodeD extends NodeC {
+        public NodeD(String name) {
+            super(name);
+        }
+    }
+
+    @Test
+    public void simpleSubclassTest() {
+        Graph graph = new Graph();
+        graph.add(new NodeB("b"));
+        graph.add(new NodeD("d"));
+
+        Assert.assertEquals("bd", TypedNodeIteratorTest.toString(graph.getNodes(NodeB.class)));
+        Assert.assertEquals("d", TypedNodeIteratorTest.toString(graph.getNodes(NodeD.class)));
+    }
+
+    @Test
+    public void addingNodeDuringIterationTest() {
+        Graph graph = new Graph();
+        graph.add(new NodeB("b1"));
+        NodeD d1 = graph.add(new NodeD("d1"));
+        StringBuilder sb = new StringBuilder();
+        for (NodeB tn : graph.getNodes(NodeB.class)) {
+            if (tn == d1) {
+                graph.add(new NodeB("b2"));
+            }
+            sb.append(tn.getName());
+        }
+        assertEquals("b1d1b2", sb.toString());
+        for (NodeB tn : graph.getNodes(NodeB.class)) {
+            if (tn == d1) {
+                graph.add(new NodeB("b3"));
+            }
+            assertNotNull(tn);
+        }
+        assertEquals(4, graph.getNodes(NodeB.class).count());
+        assertEquals(1, graph.getNodes(NodeD.class).count());
+    }
+
+}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Wed Jan 16 09:08:24 2013 +0100
@@ -310,51 +310,99 @@
         };
     }
 
-    private static class TypedNodeIterator<T extends IterableNodeType> implements Iterator<T> {
-        private Node current;
-        private final Node start;
+    private static class PlaceHolderNode extends Node {}
+    private static final PlaceHolderNode PLACE_HOLDER = new PlaceHolderNode();
+
+    private class TypedNodeIterator<T extends IterableNodeType> implements Iterator<T> {
+        private final int[] ids;
+        private final Node[] current;
+
+        private int currentIdIndex;
+        private boolean needsForward;
+
+        public TypedNodeIterator(NodeClass clazz) {
+            ids = clazz.iterableIds();
+            currentIdIndex = 0;
+            current = new Node[ids.length];
+            Arrays.fill(current, PLACE_HOLDER);
+            needsForward = true;
+        }
+
+        private Node findNext() {
+            if (needsForward) {
+                forward();
+            } else {
+                Node c = current();
+                Node afterDeleted = skipDeleted(c);
+                if (afterDeleted == null) {
+                    needsForward = true;
+                } else if (c != afterDeleted) {
+                    setCurrent(afterDeleted);
+                }
+            }
+            if (needsForward) {
+                return null;
+            }
+            return current();
+        }
 
-        public TypedNodeIterator(Node start) {
-            if (start != null && start.isDeleted()) {
-                this.current = start;
-            } else {
-                this.current = null;
+        private Node skipDeleted(Node node) {
+            Node n = node;
+            while (n != null && n.isDeleted()) {
+                n = n.typeCacheNext;
             }
-            this.start = start;
+            return n;
+        }
+
+        private void forward() {
+            needsForward = false;
+            int startIdx = currentIdIndex;
+            while (true) {
+                Node next;
+                if (current() == PLACE_HOLDER) {
+                    next = getStartNode(ids[currentIdIndex]);
+                } else {
+                    next = current().typeCacheNext;
+                }
+                next = skipDeleted(next);
+                if (next == null) {
+                    currentIdIndex++;
+                    if (currentIdIndex >= ids.length) {
+                        currentIdIndex = 0;
+                    }
+                    if (currentIdIndex == startIdx) {
+                        needsForward = true;
+                        return;
+                    }
+                } else {
+                    setCurrent(next);
+                    break;
+                }
+            }
+        }
+
+        private Node current() {
+            return current[currentIdIndex];
+        }
+
+        private void setCurrent(Node n) {
+            current[currentIdIndex] = n;
         }
 
         @Override
         public boolean hasNext() {
-            if (current != null) {
-                Node next = current.typeCacheNext;
-                if (next != null) {
-                    while (next.isDeleted()) {
-                        next = next.typeCacheNext;
-                        if (next == null) {
-                            return false;
-                        }
-                        current.typeCacheNext = next;
-                    }
-                    return true;
-                }
-                return false;
-            } else {
-                return start != null;
-            }
+            return findNext() != null;
         }
 
         @Override
         @SuppressWarnings("unchecked")
         public T next() {
-            if (current == null) {
-                Node result = start;
-                current = result;
-                return (T) result;
-            } else {
-                Node result = current.typeCacheNext;
-                current = result;
-                return (T) result;
+            Node result = findNext();
+            if (result == null) {
+                throw new NoSuchElementException();
             }
+            needsForward = true;
+            return (T) result;
         }
 
         @Override
@@ -369,11 +417,11 @@
      * @return an {@link Iterable} providing all the matching nodes.
      */
     public <T extends Node & IterableNodeType> NodeIterable<T> getNodes(final Class<T> type) {
-        final Node start = getStartNode(type);
+        final NodeClass nodeClass = NodeClass.get(type);
         return new AbstractNodeIterable<T>() {
             @Override
             public Iterator<T> iterator() {
-                return new TypedNodeIterator<>(start);
+                return new TypedNodeIterator<>(nodeClass);
             }
         };
     }
@@ -387,10 +435,8 @@
         return getNodes(type).iterator().hasNext();
     }
 
-    private <T> Node getStartNode(final Class<T> type) {
-        int nodeClassId = NodeClass.get(type).iterableId();
-        assert nodeClassId != -1 : type + " is not iterable within graphs (missing \"implements IterableNodeType\"?)";
-        Node start = nodeCacheFirst.size() <= nodeClassId ? null : nodeCacheFirst.get(nodeClassId);
+    private Node getStartNode(int iterableId) {
+        Node start = nodeCacheFirst.size() <= iterableId ? null : nodeCacheFirst.get(iterableId);
         return start;
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed Jan 16 09:08:24 2013 +0100
@@ -47,8 +47,7 @@
         }
     }
 
-
-    public static final int NOT_ITERABLE = -1;
+    static final int NOT_ITERABLE = -1;
 
     private static final Class<?> NODE_CLASS = Node.class;
     private static final Class<?> INPUT_LIST_CLASS = NodeInputList.class;
@@ -66,6 +65,7 @@
     private final String shortName;
     private final String nameTemplate;
     private final int iterableId;
+    private int[] iterableIds;
 
 
     public NodeClass(Class<?> clazz) {
@@ -110,14 +110,27 @@
         this.shortName = newShortName;
         if (Node.IterableNodeType.class.isAssignableFrom(clazz)) {
             this.iterableId = nextIterableId++;
-            // TODO (lstadler) add type hierarchy - based node iteration
-//            for (NodeClass nodeClass : nodeClasses.values()) {
-//                if (clazz.isAssignableFrom(nodeClass.clazz)) {
-//                    throw new UnsupportedOperationException("iterable non-final Node classes not supported: " + clazz);
-//                }
-//            }
+            List<NodeClass> existingClasses = new LinkedList<>();
+            for (FieldIntrospection nodeClass : allClasses.values()) {
+                if (clazz.isAssignableFrom(nodeClass.clazz)) {
+                    existingClasses.add((NodeClass) nodeClass);
+                }
+                if (nodeClass.clazz.isAssignableFrom(clazz) && Node.IterableNodeType.class.isAssignableFrom(nodeClass.clazz)) {
+                    NodeClass superNodeClass = (NodeClass) nodeClass;
+                    superNodeClass.iterableIds = Arrays.copyOf(superNodeClass.iterableIds, superNodeClass.iterableIds.length + 1);
+                    superNodeClass.iterableIds[superNodeClass.iterableIds.length - 1] = this.iterableId;
+                }
+            }
+            int[] ids = new int[existingClasses.size() + 1];
+            ids[0] = iterableId;
+            int i = 1;
+            for (NodeClass other : existingClasses) {
+                ids[i++] = other.iterableId;
+            }
+            this.iterableIds = ids;
         } else {
             this.iterableId = NOT_ITERABLE;
+            this.iterableIds = null;
         }
     }
 
@@ -145,6 +158,10 @@
         return shortName;
     }
 
+    public int[] iterableIds() {
+        return iterableIds;
+    }
+
     public int iterableId() {
         return iterableId;
     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Wed Jan 16 09:08:24 2013 +0100
@@ -62,16 +62,19 @@
         return attributesMap;
     }
 
-    private final Register[] generalParameterRegisters;
+    private final Register[] javaGeneralParameterRegisters;
+    private final Register[] nativeGeneralParameterRegisters;
     private final Register[] xmmParameterRegisters = {xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7};
 
     private final CalleeSaveLayout csl;
 
     public AMD64HotSpotRegisterConfig(HotSpotVMConfig config, boolean globalStubConfig) {
         if (config.windowsOs) {
-            generalParameterRegisters = new Register[] {rdx, r8, r9, rdi, rsi, rcx};
+            javaGeneralParameterRegisters = new Register[] {rdx, r8, r9, rdi, rsi, rcx};
+            nativeGeneralParameterRegisters = new Register[] {rcx, rdx, r8, r9};
         } else {
-            generalParameterRegisters = new Register[] {rsi, rdx, rcx, r8, r9, rdi};
+            javaGeneralParameterRegisters = new Register[] {rsi, rdx, rcx, r8, r9, rdi};
+            nativeGeneralParameterRegisters = new Register[] {rdi, rsi, rdx, rcx, r8, r9};
         }
 
         if (globalStubConfig) {
@@ -107,19 +110,19 @@
     @Override
     public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly) {
         if (type == Type.NativeCall) {
-            throw new UnsupportedOperationException();
+            return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly);
         }
-        return callingConvention(returnType, parameterTypes, type, target, stackOnly);
+        return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly);
     }
 
     public Register[] getCallingConventionRegisters(Type type, RegisterFlag flag) {
         if (flag == RegisterFlag.FPU) {
             return xmmParameterRegisters;
         }
-        return generalParameterRegisters;
+        return type == Type.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters;
     }
 
-    private CallingConvention callingConvention(JavaType returnType, JavaType[] parameterTypes, Type type, TargetDescription target, boolean stackOnly) {
+    private CallingConvention callingConvention(Register[] generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, Type type, TargetDescription target, boolean stackOnly) {
         Value[] locations = new Value[parameterTypes.length];
 
         int currentGeneral = 0;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Wed Jan 16 09:08:24 2013 +0100
@@ -25,6 +25,7 @@
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.compiler.amd64.AMD64DeoptimizationStub.*;
 import static com.oracle.graal.compiler.amd64.AMD64LIRGenerator.*;
+import static com.oracle.graal.hotspot.nodes.IdentityHashCodeStubCall.*;
 import static com.oracle.graal.hotspot.nodes.MonitorEnterStubCall.*;
 import static com.oracle.graal.hotspot.nodes.MonitorExitStubCall.*;
 import static com.oracle.graal.hotspot.nodes.NewArraySlowStubCall.*;
@@ -32,10 +33,13 @@
 import static com.oracle.graal.hotspot.nodes.NewInstanceSlowStubCall.*;
 import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*;
 import static com.oracle.graal.hotspot.nodes.NewMultiArrayStubCall.*;
+import static com.oracle.graal.hotspot.nodes.ThreadIsInterruptedStubCall.*;
 import static com.oracle.graal.hotspot.nodes.VMErrorNode.*;
 import static com.oracle.graal.hotspot.nodes.VerifyOopStubCall.*;
-import static com.oracle.graal.hotspot.nodes.IdentityHashCodeStubCall.*;
-import static com.oracle.graal.hotspot.nodes.ThreadIsInterruptedStubCall.*;
+import static com.oracle.graal.hotspot.snippets.AESCryptSubstitutions.DecryptBlockStubCall.*;
+import static com.oracle.graal.hotspot.snippets.AESCryptSubstitutions.EncryptBlockStubCall.*;
+import static com.oracle.graal.hotspot.snippets.CipherBlockChainingSubstitutions.DecryptAESCryptStubCall.*;
+import static com.oracle.graal.hotspot.snippets.CipherBlockChainingSubstitutions.EncryptAESCryptStubCall.*;
 import static com.oracle.graal.lir.amd64.AMD64Call.*;
 
 import com.oracle.graal.api.code.*;
@@ -66,26 +70,26 @@
         addRuntimeCall(ARITHMETIC_FREM, config.arithmeticFremStub,
                 /*           temps */ null,
                 /*             ret */ ret(Kind.Float),
-                /* arg0:         a */ arg(0, Kind.Float),
-                /* arg1:         b */ arg(1, Kind.Float));
+                /* arg0:         a */ jarg(0, Kind.Float),
+                /* arg1:         b */ jarg(1, Kind.Float));
 
         addRuntimeCall(ARITHMETIC_DREM, config.arithmeticDremStub,
                 /*           temps */ null,
                 /*             ret */ ret(Kind.Double),
-                /* arg0:         a */ arg(0, Kind.Double),
-                /* arg1:         b */ arg(1, Kind.Double));
+                /* arg0:         a */ jarg(0, Kind.Double),
+                /* arg1:         b */ jarg(1, Kind.Double));
 
         addRuntimeCall(MONITORENTER, config.monitorEnterStub,
                 /*        temps */ null,
                 /*          ret */ ret(Kind.Void),
-                /* arg0: object */ arg(0, Kind.Object),
-                /* arg1:   lock */ arg(1, word));
+                /* arg0: object */ jarg(0, Kind.Object),
+                /* arg1:   lock */ jarg(1, word));
 
         addRuntimeCall(MONITOREXIT, config.monitorExitStub,
                 /*        temps */ null,
                 /*          ret */ ret(Kind.Void),
-                /* arg0: object */ arg(0, Kind.Object),
-                /* arg1:   lock */ arg(1, word));
+                /* arg0: object */ jarg(0, Kind.Object),
+                /* arg1:   lock */ jarg(1, word));
 
         addRuntimeCall(NEW_ARRAY, 0L,
                 /*        temps */ null,
@@ -124,20 +128,52 @@
         addRuntimeCall(VM_ERROR, config.vmErrorStub,
                 /*        temps */ null,
                 /*          ret */ ret(Kind.Void),
-                /* arg0:  where */ arg(0, Kind.Object),
-                /* arg1: format */ arg(1, Kind.Object),
-                /* arg2:  value */ arg(2, Kind.Long));
+                /* arg0:  where */ jarg(0, Kind.Object),
+                /* arg1: format */ jarg(1, Kind.Object),
+                /* arg2:  value */ jarg(2, Kind.Long));
 
         addRuntimeCall(IDENTITY_HASHCODE, config.identityHashCodeStub,
                 /*        temps */ null,
                 /*          ret */ rax.asValue(Kind.Int),
-                /* arg0:    obj */ arg(0, Kind.Object));
+                /* arg0:    obj */ jarg(0, Kind.Object));
 
         addRuntimeCall(THREAD_IS_INTERRUPTED, config.threadIsInterruptedStub,
                 /*        temps */ null,
                 /*          ret */ rax.asValue(Kind.Int),
-                /* arg0: thread */ arg(0, Kind.Object),
-      /* arg1: clearInterrupted */ arg(1, Kind.Boolean));
+                /* arg0: thread */ jarg(0, Kind.Object),
+      /* arg1: clearInterrupted */ jarg(1, Kind.Boolean));
+
+        addRuntimeCall(ENCRYPT_BLOCK, config.aescryptEncryptBlockStub,
+                /*        temps */ null,
+                /*          ret */ ret(Kind.Void),
+                /* arg0:     in */ carg(0, word),
+                /* arg1:    out */ carg(1, word),
+                /* arg2:    key */ carg(2, word));
+
+        addRuntimeCall(DECRYPT_BLOCK, config.aescryptDecryptBlockStub,
+                /*        temps */ null,
+                /*          ret */ ret(Kind.Void),
+                /* arg0:     in */ carg(0, word),
+                /* arg1:    out */ carg(1, word),
+                /* arg2:    key */ carg(2, word));
+
+        addRuntimeCall(ENCRYPT, config.cipherBlockChainingEncryptAESCryptStub,
+                /*        temps */ null,
+                /*          ret */ ret(Kind.Void),
+                /* arg0:     in */ carg(0, word),
+                /* arg1:    out */ carg(1, word),
+                /* arg2:    key */ carg(2, word),
+                /* arg3:      r */ carg(3, word),
+              /* arg4: inLength */ carg(4, Kind.Int));
+
+        addRuntimeCall(DECRYPT, config.cipherBlockChainingDecryptAESCryptStub,
+                /*        temps */ null,
+                /*          ret */ ret(Kind.Void),
+                /* arg0:     in */ carg(0, word),
+                /* arg1:    out */ carg(1, word),
+                /* arg2:    key */ carg(2, word),
+                /* arg3:      r */ carg(3, word),
+              /* arg4: inLength */ carg(4, Kind.Int));
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed Jan 16 09:08:24 2013 +0100
@@ -22,11 +22,14 @@
  */
 package com.oracle.graal.hotspot;
 
+import static com.oracle.graal.nodes.StructuredGraph.*;
+
 import java.util.concurrent.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
@@ -127,7 +130,14 @@
                     @Override
                     public CompilationResult call() throws Exception {
                         graalRuntime.evictDeoptedGraphs();
-                        StructuredGraph graph = new StructuredGraph(method, entryBCI);
+                        StructuredGraph graph = (StructuredGraph) method.getCompilerStorage().get(Graph.class);
+                        if (graph == null || entryBCI != INVOCATION_ENTRY_BCI) {
+                            graph = new StructuredGraph(method, entryBCI);
+                        } else {
+                            // Compiling an intrinsic graph - must clone the graph
+                            graph = graph.copy();
+                            //System.out.println("compiling intrinsic " + method);
+                        }
                         return graalRuntime.getCompiler().compileMethod(method, graph, graalRuntime.getCache(), plan, optimisticOpts);
                     }
                 });
@@ -183,4 +193,9 @@
         return id < o.id ? -1 : (id > o.id ? 1 : 0);
     }
 
+    @Override
+    public String toString() {
+        return "Compilation[id=" + id + ", prio=" + priority + " " + MetaUtil.format("%H.%n(%p)", method) +
+                        (entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI ? "" : "@" + entryBCI) + "]";
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerThread.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerThread.java	Wed Jan 16 09:08:24 2013 +0100
@@ -25,8 +25,10 @@
 import java.io.*;
 import java.util.concurrent.*;
 
+import com.oracle.graal.compiler.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.phases.*;
+import com.oracle.graal.printer.*;
 
 
 public final class CompilerThread extends Thread {
@@ -56,12 +58,10 @@
 
     @Override
     public void run() {
-        HotSpotDebugConfig hotspotDebugConfig = null;
+        GraalDebugConfig hotspotDebugConfig = null;
         if (GraalOptions.Debug) {
-            Debug.enable();
             PrintStream log = HotSpotGraalRuntime.getInstance().getVMToCompiler().log();
-            hotspotDebugConfig = new HotSpotDebugConfig(GraalOptions.Log, GraalOptions.Meter, GraalOptions.Time, GraalOptions.Dump, GraalOptions.MethodFilter, log);
-            Debug.setConfig(hotspotDebugConfig);
+            DebugEnvironment.initialize(log);
         }
         try {
             super.run();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/DebugFilter.java	Wed Jan 16 09:05:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
-/*
- * Copyright (c) 2012, 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;
-
-import static com.oracle.graal.hotspot.MethodFilter.*;
-
-import java.util.*;
-import java.util.regex.*;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.internal.*;
-import com.oracle.graal.phases.*;
-
-/**
- * Implements the filter specified by the {@link GraalOptions#Dump},
- * {@link GraalOptions#Log}, {@link GraalOptions#Meter} and {@link GraalOptions#Time}
- * options.
- * <p>
- * These options enable the associated debug facility if their filter
- * matches the {@linkplain DebugScope#getQualifiedName() name} of the
- * {@linkplain Debug#currentScope() current scope}.
- * <p>
- * A filter is a list of comma-separated terms. Each term is interpreted
- * as a glob pattern if it contains a "*" or "?" character. Otherwise, it is
- * interpreted as a substring. If a term starts with "~", then it is an
- * positive term. An input is matched by a filter if any of its positive
- * terms match the input (or it has no positive terms) AND none of its
- * negative terms match the input (or it has no negative terms).
- * <p>
- * Examples of filters include:
- * <p>
- * <ul>
- * <li><pre>""</pre>
- * Matches any scope.</li>
- * <li><pre>"*"</pre>
- * Matches any scope.</li>
- * <li><pre>"CodeGen,CodeInstall"</pre>
- * Matches a scope whose name contains "CodeGen" or "CodeInstall".</li>
- * <li><pre>"Code*"</pre>
- * Matches a scope whose name starts with "Code".</li>
- * <li><pre>"Code,~Dead"</pre>
- * Matches a scope whose name contains "Code" but does not contain "Dead".</li>
- * </ul>
- */
-class DebugFilter {
-
-    public static DebugFilter parse(String spec) {
-        if (spec == null) {
-            return null;
-        }
-        return new DebugFilter(spec.split(","));
-    }
-
-    final Term[] positive;
-    final Term[] negative;
-
-    DebugFilter(String[] terms) {
-        List<Term> pos = new ArrayList<>(terms.length);
-        List<Term> neg = new ArrayList<>(terms.length);
-        for (int i = 0; i < terms.length; i++) {
-            String t = terms[i];
-            if (t.startsWith("~")) {
-                neg.add(new Term(t.substring(1)));
-            } else {
-                pos.add(new Term(t));
-            }
-        }
-        this.positive = pos.isEmpty() ? null : pos.toArray(new Term[pos.size()]);
-        this.negative = neg.isEmpty() ? null : neg.toArray(new Term[neg.size()]);
-    }
-
-    /**
-     * Determines if a given input is matched by this filter.
-     */
-    public boolean matches(String input) {
-        boolean match = true;
-        if (positive != null) {
-            match = false;
-            for (Term t : positive) {
-                if (t.matches(input)) {
-                    match = true;
-                    break;
-                }
-            }
-        }
-        if (match && negative != null) {
-            for (Term t : negative) {
-                if (t.matches(input)) {
-                    match = false;
-                    break;
-                }
-            }
-        }
-//        if (match) {
-//            System.out.println(this + " matches " + input);
-//        }
-        return match;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder buf = new StringBuilder("DebugFilter[");
-        String sep = "";
-        if (positive != null) {
-            buf.append(sep).append("pos=").append(Arrays.toString(positive));
-            sep = ", ";
-        }
-        if (negative != null) {
-            buf.append(sep).append("neg=").append(Arrays.toString(negative));
-            sep = ", ";
-        }
-        return buf.append("]").toString();
-    }
-
-    static class Term {
-
-        final Pattern pattern;
-
-        public Term(String filter) {
-            if (filter.isEmpty()) {
-                this.pattern = null;
-            } else if (filter.contains("*") || filter.contains("?")) {
-                this.pattern = Pattern.compile(createGlobString(filter));
-            } else {
-                this.pattern = Pattern.compile(".*" + createGlobString(filter) + ".*");
-            }
-        }
-
-        /**
-         * Determines if a given input is matched by this filter.
-         */
-        public boolean matches(String input) {
-            return pattern == null || pattern.matcher(input).matches();
-        }
-
-        @Override
-        public String toString() {
-            return pattern == null ? ".*" : pattern.toString();
-        }
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java	Wed Jan 16 09:05:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,193 +0,0 @@
-/*
- * Copyright (c) 2012, 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;
-
-import java.io.*;
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.printer.*;
-
-public class HotSpotDebugConfig implements DebugConfig {
-
-    private final DebugFilter logFilter;
-    private final DebugFilter meterFilter;
-    private final DebugFilter timerFilter;
-    private final DebugFilter dumpFilter;
-    private final MethodFilter[] methodFilter;
-    private final List<DebugDumpHandler> dumpHandlers = new ArrayList<>();
-    private final PrintStream output;
-    private final Set<Object> extraFilters = new HashSet<>();
-
-    public HotSpotDebugConfig(String logFilter, String meterFilter, String timerFilter, String dumpFilter, String methodFilter, PrintStream output) {
-        this.logFilter = DebugFilter.parse(logFilter);
-        this.meterFilter = DebugFilter.parse(meterFilter);
-        this.timerFilter = DebugFilter.parse(timerFilter);
-        this.dumpFilter = DebugFilter.parse(dumpFilter);
-        if (methodFilter == null || methodFilter.isEmpty()) {
-            this.methodFilter = null;
-        } else {
-            String[] filters = methodFilter.split(",");
-            this.methodFilter = new MethodFilter[filters.length];
-            for (int i = 0; i < filters.length; i++) {
-                this.methodFilter[i] = new MethodFilter(filters[i]);
-            }
-        }
-
-        // Report the filters that have been configured so the user can verify it's what they expect
-        if (logFilter != null || meterFilter != null || timerFilter != null || dumpFilter != null || methodFilter != null) {
-            TTY.println(Thread.currentThread().getName() + ": " + toString());
-        }
-        dumpHandlers.add(new GraphPrinterDumpHandler());
-        if (GraalOptions.PrintCFG) {
-            if (GraalOptions.PrintBinaryGraphs) {
-                TTY.println("CFG dumping slows down PrintBinaryGraphs: use -G:-PrintCFG to disable it");
-            }
-            dumpHandlers.add(new CFGPrinterObserver());
-        }
-        this.output = output;
-    }
-
-    public boolean isLogEnabled() {
-        return isEnabled(logFilter);
-    }
-
-    public boolean isMeterEnabled() {
-        return isEnabled(meterFilter);
-    }
-
-    public boolean isDumpEnabled() {
-        return isEnabled(dumpFilter);
-    }
-
-    public boolean isTimeEnabled() {
-        return isEnabled(timerFilter);
-    }
-
-    public PrintStream output() {
-        return output;
-    }
-
-    private boolean isEnabled(DebugFilter filter) {
-        return checkDebugFilter(Debug.currentScope(), filter) && checkMethodFilter();
-    }
-
-    private static boolean checkDebugFilter(String currentScope, DebugFilter filter) {
-        return filter != null && filter.matches(currentScope);
-    }
-
-    private boolean checkMethodFilter() {
-        if (methodFilter == null && extraFilters.isEmpty()) {
-            return true;
-        } else {
-            for (Object o : Debug.context()) {
-                if (extraFilters.contains(o)) {
-                    return true;
-                } else if (methodFilter != null) {
-                    if (o instanceof JavaMethod) {
-                        for (MethodFilter filter : methodFilter) {
-                            if (filter.matches((JavaMethod) o)) {
-                                return true;
-                            }
-                        }
-                    }
-                }
-            }
-            return false;
-        }
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("Debug config:");
-        add(sb, "Log", logFilter);
-        add(sb, "Meter", meterFilter);
-        add(sb, "Time", timerFilter);
-        add(sb, "Dump", dumpFilter);
-        add(sb, "MethodFilter", methodFilter);
-        return sb.toString();
-    }
-
-    private static void add(StringBuilder sb, String name, Object filter) {
-        if (filter != null) {
-            sb.append(' ');
-            sb.append(name);
-            sb.append('=');
-            if (filter instanceof Object[]) {
-                sb.append(Arrays.toString((Object[]) filter));
-            } else {
-                sb.append(String.valueOf(filter));
-            }
-        }
-    }
-
-    @Override
-    public RuntimeException interceptException(Throwable e) {
-        if (e instanceof BailoutException) {
-            return null;
-        }
-        Debug.setConfig(Debug.fixedConfig(true, true, false, false, dumpHandlers, output));
-        Debug.log(String.format("Exception occurred in scope: %s", Debug.currentScope()));
-        for (Object o : Debug.context()) {
-            if (o instanceof Graph) {
-                Debug.log("Context obj %s", o);
-                if (GraalOptions.DumpOnError) {
-                    Debug.dump(o, "Exception graph");
-                } else {
-                    Debug.log("Use -G:+DumpOnError to enable dumping of graphs on this error");
-                }
-            } else if (o instanceof Node) {
-                String location = GraphUtil.approxSourceLocation((Node) o);
-                if (location != null) {
-                    Debug.log("Context obj %s (approx. location: %s)", o, location);
-                } else {
-                    Debug.log("Context obj %s", o);
-                }
-            } else {
-                Debug.log("Context obj %s", o);
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public Collection<DebugDumpHandler> dumpHandlers() {
-        return dumpHandlers;
-    }
-
-    @Override
-    public void addToContext(Object o) {
-        extraFilters.add(o);
-    }
-
-    @Override
-    public void removeFromContext(Object o) {
-        extraFilters.remove(o);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotSnippetInstaller.java	Wed Jan 16 09:08:24 2013 +0100
@@ -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.hotspot;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.snippets.*;
+import com.oracle.graal.snippets.*;
+
+/**
+ * Filters certain intrinsifications based on whether there is underlying hardware support for them.
+ */
+public class HotSpotSnippetInstaller extends SnippetInstaller {
+
+    private final HotSpotVMConfig config;
+
+    public HotSpotSnippetInstaller(HotSpotRuntime runtime, Assumptions assumptions, TargetDescription target) {
+        super(runtime, assumptions, target);
+        this.config = runtime.config;
+    }
+
+    @Override
+    protected void installSubstitution(Method originalMethod, Method substituteMethod) {
+        if (substituteMethod.getDeclaringClass() == IntegerSubstitutions.class || substituteMethod.getDeclaringClass() == LongSubstitutions.class) {
+            if (substituteMethod.getName().equals("bitCount")) {
+                if (!config.usePopCountInstruction) {
+                    return;
+                }
+            }
+        } else if (substituteMethod.getDeclaringClass() == AESCryptSubstitutions.class || substituteMethod.getDeclaringClass() == CipherBlockChainingSubstitutions.class) {
+            if (!config.useAESIntrinsics) {
+                return;
+            }
+            assert config.aescryptEncryptBlockStub != 0L;
+            assert config.aescryptDecryptBlockStub != 0L;
+            assert config.cipherBlockChainingEncryptAESCryptStub != 0L;
+            assert config.cipherBlockChainingDecryptAESCryptStub != 0L;
+        }
+        super.installSubstitution(originalMethod, substituteMethod);
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Wed Jan 16 09:08:24 2013 +0100
@@ -40,6 +40,8 @@
     public boolean useFastLocking;
     public boolean useTLAB;
     public boolean useBiasedLocking;
+    public boolean usePopCountInstruction;
+    public boolean useAESIntrinsics;
 
     // offsets, ...
     public int vmPageSize;
@@ -334,6 +336,10 @@
     public int deoptReasonNone;
     public long threadIsInterruptedStub;
     public long identityHashCodeStub;
+    public long aescryptEncryptBlockStub;
+    public long aescryptDecryptBlockStub;
+    public long cipherBlockChainingEncryptAESCryptStub;
+    public long cipherBlockChainingDecryptAESCryptStub;
 
     public int deoptReasonNullCheck;
     public int deoptReasonRangeCheck;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/MethodFilter.java	Wed Jan 16 09:05:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +0,0 @@
-/*
- * Copyright (c) 2012, 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;
-
-import java.util.*;
-import java.util.regex.*;
-
-import com.oracle.graal.api.meta.*;
-
-/**
- * This class implements a method filter that can filter based on class name, method name and parameters.
- * The syntax for the source pattern that is passed to the constructor is as follows:
- *
- * <pre>
- * SourcePattern = [ Class "." ] method [ "(" [ Parameter { ";" Parameter } ] ")" ] .
- * Parameter = Class | "int" | "long" | "float" | "double" | "short" | "char" | "boolean" .
- * Class = { package "." } class .
- * </pre>
- *
- *
- * Glob pattern matching (*, ?) is allowed in all parts of the source pattern. Examples for valid filters are:
- *
- * <ul>
- * <li><pre>visit(Argument;BlockScope)</pre>
- * Matches all methods named "visit", with the first parameter of type "Argument", and the second parameter of type "BlockScope".
- * The packages of the parameter types are irrelevant.</li>
- * <li><pre>arraycopy(Object;;;;)</pre>
- * Matches all methods named "arraycopy", with the first parameter of type "Object", and four more parameters of any type.
- * The packages of the parameter types are irrelevant.</li>
- * <li><pre>com.oracle.graal.compiler.graph.PostOrderNodeIterator.*</pre>
- * Matches all methods in the class "com.oracle.graal.compiler.graph.PostOrderNodeIterator".</li>
- * <li><pre>*</pre>
- * Matches all methods in all classes</li>
- * <li><pre>com.oracle.graal.compiler.graph.*.visit</pre>
- * Matches all methods named "visit" in classes in the package "com.oracle.graal.compiler.graph".</pre>
- * </ul>
- */
-public class MethodFilter {
-
-    private final Pattern clazz;
-    private final Pattern methodName;
-    private final Pattern[] signature;
-
-    public MethodFilter(String sourcePattern) {
-        String pattern = sourcePattern.trim();
-
-        // extract parameter part
-        int pos = pattern.indexOf('(');
-        if (pos != -1) {
-            if (pattern.charAt(pattern.length() - 1) != ')') {
-                throw new IllegalArgumentException("missing ')' at end of method filter pattern: " + pattern);
-            }
-            String[] signatureClasses = pattern.substring(pos + 1, pattern.length() - 1).split(";", -1);
-            signature = new Pattern[signatureClasses.length];
-            for (int i = 0; i < signatureClasses.length; i++) {
-                signature[i] = createClassGlobPattern(signatureClasses[i].trim());
-            }
-            pattern = pattern.substring(0, pos);
-        } else {
-            signature = null;
-        }
-
-        // If there is at least one "." then everything before the last "." is the class name.
-        // Otherwise, the pattern contains only the method name.
-        pos = pattern.lastIndexOf('.');
-        if (pos != -1) {
-            clazz = createClassGlobPattern(pattern.substring(0, pos));
-            methodName = Pattern.compile(createGlobString(pattern.substring(pos + 1)));
-        } else {
-            clazz = null;
-            methodName = Pattern.compile(createGlobString(pattern));
-        }
-    }
-
-    static String createGlobString(String pattern) {
-        return Pattern.quote(pattern).replace("?", "\\E.\\Q").replace("*", "\\E.*\\Q");
-    }
-
-    private static Pattern createClassGlobPattern(String pattern) {
-        if (pattern.length() == 0) {
-            return null;
-        } else if (pattern.contains(".")) {
-            return Pattern.compile(createGlobString(pattern));
-        } else {
-            return Pattern.compile("([^\\.]*\\.)*" + createGlobString(pattern));
-        }
-    }
-
-    public boolean matches(JavaMethod o) {
-        // check method name first, since MetaUtil.toJavaName is expensive
-        if (methodName != null && !methodName.matcher(o.getName()).matches()) {
-            return false;
-        }
-        if (clazz != null && !clazz.matcher(MetaUtil.toJavaName(o.getDeclaringClass())).matches()) {
-            return false;
-        }
-        if (signature != null) {
-            Signature sig = o.getSignature();
-            if (sig.getParameterCount(false) != signature.length) {
-                return false;
-            }
-            for (int i = 0; i < signature.length; i++) {
-                JavaType type = sig.getParameterType(i, null);
-                String javaName = MetaUtil.toJavaName(type);
-                if (signature[i] != null && !signature[i].matcher(javaName).matches()) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder buf = new StringBuilder("MethodFilter[");
-        String sep = "";
-        if (clazz != null) {
-            buf.append(sep).append("clazz=").append(clazz);
-            sep = ", ";
-        }
-        if (methodName != null) {
-            buf.append(sep).append("methodName=").append(methodName);
-            sep = ", ";
-        }
-        if (signature != null) {
-            buf.append(sep).append("signature=").append(Arrays.toString(signature));
-            sep = ", ";
-        }
-        return buf.append("]").toString();
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Wed Jan 16 09:08:24 2013 +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	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Wed Jan 16 09:08:24 2013 +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);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed Jan 16 09:08:24 2013 +0100
@@ -23,7 +23,7 @@
 
 package com.oracle.graal.hotspot.bridge;
 
-import static com.oracle.graal.graph.FieldIntrospection.*;
+import static com.oracle.graal.graph.UnsafeAccess.*;
 
 import java.io.*;
 import java.lang.reflect.*;
@@ -44,6 +44,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.PhasePlan.PhasePosition;
+import com.oracle.graal.printer.*;
 import com.oracle.graal.snippets.*;
 
 /**
@@ -125,9 +126,11 @@
 
         if (GraalOptions.Debug) {
             Debug.enable();
-            HotSpotDebugConfig hotspotDebugConfig = new HotSpotDebugConfig(GraalOptions.Log, GraalOptions.Meter, GraalOptions.Time, GraalOptions.Dump, GraalOptions.MethodFilter, log);
-            Debug.setConfig(hotspotDebugConfig);
+            if (GraalOptions.DebugSnippets) {
+                DebugEnvironment.initialize(log);
+            }
         }
+
         // Install intrinsics.
         GraalCompiler compiler = graalRuntime.getCompiler();
         final HotSpotRuntime runtime = (HotSpotRuntime) compiler.runtime;
@@ -139,7 +142,7 @@
                     // Snippets cannot have speculative optimizations since they have to be valid for the entire run of the VM.
                     Assumptions assumptions = new Assumptions(false);
                     VMToCompilerImpl.this.intrinsifyArrayCopy = new IntrinsifyArrayCopyPhase(runtime, assumptions);
-                    SnippetInstaller installer = new SnippetInstaller(runtime, assumptions, runtime.getGraalRuntime().getTarget());
+                    SnippetInstaller installer = new HotSpotSnippetInstaller(runtime, assumptions, runtime.getGraalRuntime().getTarget());
                     GraalIntrinsics.installIntrinsics(installer);
                     runtime.installSnippets(installer, assumptions);
                 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LineNumberTableImpl.java	Wed Jan 16 09:08:24 2013 +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	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Wed Jan 16 09:08:24 2013 +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	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java	Wed Jan 16 09:08:24 2013 +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	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Wed Jan 16 09:08:24 2013 +0100
@@ -330,7 +330,7 @@
     @Override
     public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method) {
         assert method instanceof HotSpotMethod;
-        return (ResolvedJavaMethod) HotSpotGraalRuntime.getInstance().getCompilerToVM().resolveMethod(this, method.getName(), ((HotSpotSignature) method.getSignature()).asString());
+        return (ResolvedJavaMethod) HotSpotGraalRuntime.getInstance().getCompilerToVM().resolveMethod(this, method.getName(), ((HotSpotSignature) method.getSignature()).getMethodDescriptor());
     }
 
     @Override
@@ -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	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java	Wed Jan 16 09:08:24 2013 +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.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Wed Jan 16 09:08:24 2013 +0100
@@ -24,15 +24,17 @@
 
 import static com.oracle.graal.api.code.DeoptimizationAction.*;
 import static com.oracle.graal.api.code.MemoryBarriers.*;
+import static com.oracle.graal.api.code.Register.RegisterFlag.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.api.meta.Value.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.hotspot.snippets.SystemSnippets.*;
+import static com.oracle.graal.hotspot.snippets.SystemSubstitutions.*;
 import static com.oracle.graal.java.GraphBuilderPhase.*;
 import static com.oracle.graal.nodes.UnwindNode.*;
 import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*;
 import static com.oracle.graal.snippets.Log.*;
-import static com.oracle.graal.snippets.MathSnippetsX86.*;
+import static com.oracle.graal.snippets.MathSubstitutionsX86.*;
+import static com.oracle.graal.api.code.CallingConvention.Type.*;
 
 import java.lang.reflect.*;
 import java.util.*;
@@ -164,11 +166,14 @@
         return globalStubRegConfig.getReturnRegister(kind).asValue(kind);
     }
 
-    protected Value arg(int index, Kind kind) {
-        if (kind == Kind.Float || kind == Kind.Double) {
-            return globalStubRegConfig.getCallingConventionRegisters(CallingConvention.Type.RuntimeCall, RegisterFlag.FPU)[index].asValue(kind);
-        }
-        return globalStubRegConfig.getCallingConventionRegisters(CallingConvention.Type.RuntimeCall, RegisterFlag.CPU)[index].asValue(kind);
+    protected Value jarg(int index, Kind kind) {
+        RegisterFlag flag = kind == Kind.Float || kind == Kind.Double ? FPU : CPU;
+        return globalStubRegConfig.getCallingConventionRegisters(RuntimeCall, flag)[index].asValue(kind);
+    }
+
+    protected Value carg(int index, Kind kind) {
+        RegisterFlag flag = kind == Kind.Float || kind == Kind.Double ? FPU : CPU;
+        return globalStubRegConfig.getCallingConventionRegisters(NativeCall, flag)[index].asValue(kind);
     }
 
     protected Value scratch(Kind kind) {
@@ -184,17 +189,17 @@
         addRuntimeCall(UNWIND_EXCEPTION, config.unwindExceptionStub,
                         /*           temps */ null,
                         /*             ret */ ret(Kind.Void),
-                        /* arg0: exception */ arg(0, Kind.Object));
+                        /* arg0: exception */ jarg(0, Kind.Object));
 
         addRuntimeCall(OnStackReplacementPhase.OSR_MIGRATION_END, config.osrMigrationEndStub,
                         /*           temps */ null,
                         /*             ret */ ret(Kind.Void),
-                        /* arg0:      long */ arg(0, Kind.Long));
+                        /* arg0:      long */ jarg(0, Kind.Long));
 
         addRuntimeCall(REGISTER_FINALIZER, config.registerFinalizerStub,
                         /*           temps */ null,
                         /*             ret */ ret(Kind.Void),
-                        /* arg0:    object */ arg(0, Kind.Object));
+                        /* arg0:    object */ jarg(0, Kind.Object));
 
         addRuntimeCall(CREATE_NULL_POINTER_EXCEPTION, config.createNullPointerExceptionStub,
                         /*           temps */ null,
@@ -203,7 +208,7 @@
         addRuntimeCall(CREATE_OUT_OF_BOUNDS_EXCEPTION, config.createOutOfBoundsExceptionStub,
                         /*           temps */ null,
                         /*             ret */ ret(Kind.Object),
-                        /* arg0:     index */ arg(0, Kind.Int));
+                        /* arg0:     index */ jarg(0, Kind.Int));
 
         addRuntimeCall(JAVA_TIME_MILLIS, config.javaTimeMillisStub,
                         /*           temps */ null,
@@ -216,38 +221,38 @@
         addRuntimeCall(ARITHMETIC_SIN, config.arithmeticSinStub,
                         /*           temps */ null,
                         /*             ret */ ret(Kind.Double),
-                        /* arg0:     index */ arg(0, Kind.Double));
+                        /* arg0:     index */ jarg(0, Kind.Double));
 
         addRuntimeCall(ARITHMETIC_COS, config.arithmeticCosStub,
                         /*           temps */ null,
                         /*             ret */ ret(Kind.Double),
-                        /* arg0:     index */ arg(0, Kind.Double));
+                        /* arg0:     index */ jarg(0, Kind.Double));
 
         addRuntimeCall(ARITHMETIC_TAN, config.arithmeticTanStub,
                         /*           temps */ null,
                         /*             ret */ ret(Kind.Double),
-                        /* arg0:     index */ arg(0, Kind.Double));
+                        /* arg0:     index */ jarg(0, Kind.Double));
 
         addRuntimeCall(LOG_PRIMITIVE, config.logPrimitiveStub,
                         /*           temps */ null,
                         /*             ret */ ret(Kind.Void),
-                        /* arg0:  typeChar */ arg(0, Kind.Int),
-                        /* arg1:     value */ arg(1, Kind.Long),
-                        /* arg2:   newline */ arg(2, Kind.Boolean));
+                        /* arg0:  typeChar */ jarg(0, Kind.Int),
+                        /* arg1:     value */ jarg(1, Kind.Long),
+                        /* arg2:   newline */ jarg(2, Kind.Boolean));
 
         addRuntimeCall(LOG_PRINTF, config.logPrintfStub,
                         /*           temps */ null,
                         /*             ret */ ret(Kind.Void),
-                        /* arg0:    format */ arg(0, Kind.Object),
-                        /* arg1:     value */ arg(1, Kind.Long),
-                        /* arg2:     value */ arg(2, Kind.Long),
-                        /* arg3:     value */ arg(3, Kind.Long));
+                        /* arg0:    format */ jarg(0, Kind.Object),
+                        /* arg1:     value */ jarg(1, Kind.Long),
+                        /* arg2:     value */ jarg(2, Kind.Long),
+                        /* arg3:     value */ jarg(3, Kind.Long));
 
         addRuntimeCall(LOG_OBJECT, config.logObjectStub,
                         /*           temps */ null,
                         /*             ret */ ret(Kind.Void),
-                        /* arg0:    object */ arg(0, Kind.Object),
-                        /* arg1:     flags */ arg(1, Kind.Int));
+                        /* arg0:    object */ jarg(0, Kind.Object),
+                        /* arg1:     flags */ jarg(1, Kind.Int));
     }
 
 
@@ -303,31 +308,35 @@
 
     public void installSnippets(SnippetInstaller installer, Assumptions assumptions) {
         if (GraalOptions.IntrinsifyObjectMethods) {
-            installer.install(ObjectSnippets.class);
+            installer.installSubstitutions(ObjectSubstitutions.class);
         }
         if (GraalOptions.IntrinsifySystemMethods) {
-            installer.install(SystemSnippets.class);
+            installer.installSubstitutions(SystemSubstitutions.class);
         }
         if (GraalOptions.IntrinsifyThreadMethods) {
-            installer.install(ThreadSnippets.class);
+            installer.installSubstitutions(ThreadSubstitutions.class);
         }
         if (GraalOptions.IntrinsifyUnsafeMethods) {
-            installer.install(UnsafeSnippets.class);
+            installer.installSubstitutions(UnsafeSubstitutions.class);
         }
         if (GraalOptions.IntrinsifyClassMethods) {
-            installer.install(ClassSnippets.class);
+            installer.installSubstitutions(ClassSubstitutions.class);
+        }
+        if (GraalOptions.IntrinsifyAESMethods) {
+            installer.installSubstitutions(AESCryptSubstitutions.class);
+            installer.installSubstitutions(CipherBlockChainingSubstitutions.class);
         }
         if (GraalOptions.IntrinsifyArrayCopy) {
-            installer.install(ArrayCopySnippets.class);
+            installer.installSnippets(ArrayCopySnippets.class);
         }
 
-        installer.install(CheckCastSnippets.class);
-        installer.install(InstanceOfSnippets.class);
-        installer.install(NewObjectSnippets.class);
-        installer.install(MonitorSnippets.class);
+        installer.installSnippets(CheckCastSnippets.class);
+        installer.installSnippets(InstanceOfSnippets.class);
+        installer.installSnippets(NewObjectSnippets.class);
+        installer.installSnippets(MonitorSnippets.class);
 
-        installer.install(NewInstanceStub.class);
-        installer.install(NewArrayStub.class);
+        installer.installSnippets(NewInstanceStub.class);
+        installer.installSnippets(NewArrayStub.class);
 
         checkcastSnippets = new CheckCastSnippets.Templates(this, assumptions, graalRuntime.getTarget());
         instanceofSnippets = new InstanceOfSnippets.Templates(this, assumptions, graalRuntime.getTarget());
@@ -458,6 +467,11 @@
     }
 
     @Override
+    public Signature parseMethodDescriptor(String signature) {
+        return new HotSpotSignature(signature);
+    }
+
+    @Override
     public int getSizeOfLockData() {
         return config.basicLockSize;
     }
@@ -702,6 +716,8 @@
             newObjectSnippets.lower((InitializeArrayNode) n, tool);
         } else if (n instanceof NewMultiArrayNode) {
             newObjectSnippets.lower((NewMultiArrayNode) n, tool);
+        } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) {
+            // Nothing to do for division nodes. The HotSpot signal handler catches divisions by zero and the MIN_VALUE / -1 cases.
         } else {
             assert false : "Node implementing Lowerable not handled: " + n;
             throw GraalInternalError.shouldNotReachHere();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java	Wed Jan 16 09:08:24 2013 +0100
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.java.*;
 
@@ -86,7 +87,7 @@
             case 'Z':
                 break;
             default:
-                assert false;
+                throw new GraalInternalError("Invalid character at index " + cur + " in signature: " + signature);
         }
         return cur;
     }
@@ -123,7 +124,8 @@
         return type;
     }
 
-    public String asString() {
+    @Override
+    public String getMethodDescriptor() {
         return originalString;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/AESCryptSubstitutions.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2012, 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.snippets;
+
+import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
+import sun.misc.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.snippets.*;
+import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution;
+import com.oracle.graal.word.*;
+
+/**
+ * Substitutions for {@code com.sun.crypto.provider.AESCrypt} methods.
+ */
+@ClassSubstitution(className = "com.sun.crypto.provider.AESCrypt")
+public class AESCryptSubstitutions {
+
+    static final long kOffset;
+    static final Class<?> AESCryptClass;
+
+    static {
+        try {
+            // Need to use launcher class path as com.sun.crypto.provider.AESCrypt
+            // is normally not on the boot class path
+            ClassLoader cl = Launcher.getLauncher().getClassLoader();
+            AESCryptClass = Class.forName("com.sun.crypto.provider.AESCrypt", true, cl);
+            kOffset = UnsafeAccess.unsafe.objectFieldOffset(AESCryptClass.getDeclaredField("K"));
+        } catch (Exception ex) {
+            throw new GraalInternalError(ex);
+        }
+    }
+
+    @MethodSubstitution(isStatic = false)
+    static void encryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) {
+        Word kAddr = Word.fromObject(rcvr).readWord(Word.unsigned(kOffset)).add(arrayBaseOffset(Kind.Byte));
+        Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset);
+        Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset);
+        EncryptBlockStubCall.call(inAddr, outAddr, kAddr);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    static void decryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) {
+        Word kAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(kOffset)).add(arrayBaseOffset(Kind.Byte));
+        Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset);
+        Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset);
+        DecryptBlockStubCall.call(inAddr, outAddr, kAddr);
+    }
+
+    public static class EncryptBlockStubCall extends FixedWithNextNode implements LIRGenLowerable {
+
+        @Input private final ValueNode in;
+        @Input private final ValueNode out;
+        @Input private final ValueNode key;
+
+        public static final Descriptor ENCRYPT_BLOCK = new Descriptor("encrypt_block", false, void.class, Word.class, Word.class, Word.class);
+
+        public EncryptBlockStubCall(ValueNode in, ValueNode out, ValueNode key) {
+            super(StampFactory.forVoid());
+            this.in = in;
+            this.out = out;
+            this.key = key;
+        }
+
+        @Override
+        public void generate(LIRGenerator gen) {
+            RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(ENCRYPT_BLOCK);
+            gen.emitCall(stub, stub.getCallingConvention(), false, gen.operand(in), gen.operand(out), gen.operand(key));
+        }
+
+        @NodeIntrinsic
+        public static native void call(Word in, Word out, Word key);
+    }
+
+    public static class DecryptBlockStubCall extends FixedWithNextNode implements LIRGenLowerable {
+
+        @Input private final ValueNode in;
+        @Input private final ValueNode out;
+        @Input private final ValueNode key;
+
+        public static final Descriptor DECRYPT_BLOCK = new Descriptor("decrypt_block", false, void.class, Word.class, Word.class, Word.class);
+
+        public DecryptBlockStubCall(ValueNode in, ValueNode out, ValueNode key) {
+            super(StampFactory.forVoid());
+            this.in = in;
+            this.out = out;
+            this.key = key;
+        }
+
+        @Override
+        public void generate(LIRGenerator gen) {
+            RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(DECRYPT_BLOCK);
+            gen.emitCall(stub, stub.getCallingConvention(), false, gen.operand(in), gen.operand(out), gen.operand(key));
+        }
+
+        @NodeIntrinsic
+        public static native void call(Word in, Word out, Word key);
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Wed Jan 16 09:08:24 2013 +0100
@@ -25,6 +25,7 @@
 import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
 import static com.oracle.graal.snippets.SnippetTemplate.*;
 import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*;
+import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -68,11 +69,13 @@
                     @Parameter("exactHub") Word exactHub,
                     @ConstantParameter("checkNull") boolean checkNull) {
         if (checkNull && object == null) {
+            probability(0.1);
             isNull.inc();
             return object;
         }
         Word objectHub = loadHub(object);
         if (objectHub != exactHub) {
+            probability(0.01);
             exactMiss.inc();
             //bkpt(object, exactHub, objectHub);
             DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.ClassCastException);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CipherBlockChainingSubstitutions.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2012, 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.snippets;
+
+import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
+import sun.misc.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.snippets.*;
+import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution;
+import com.oracle.graal.snippets.Snippet.Fold;
+import com.oracle.graal.word.*;
+
+/**
+ * Substitutions for {@code com.sun.crypto.provider.CipherBlockChaining} methods.
+ */
+@ClassSubstitution(className = "com.sun.crypto.provider.CipherBlockChaining")
+public class CipherBlockChainingSubstitutions {
+
+    private static final long embeddedCipherOffset;
+    private static final long rOffset;
+    static {
+        try {
+            // Need to use launcher class path as com.sun.crypto.provider.AESCrypt
+            // is normally not on the boot class path
+            ClassLoader cl = Launcher.getLauncher().getClassLoader();
+            embeddedCipherOffset = UnsafeAccess.unsafe.objectFieldOffset(Class.forName("com.sun.crypto.provider.FeedbackCipher", true, cl).getDeclaredField("embeddedCipher"));
+            rOffset = UnsafeAccess.unsafe.objectFieldOffset(Class.forName("com.sun.crypto.provider.CipherBlockChaining", true, cl).getDeclaredField("r"));
+        } catch (Exception ex) {
+            throw new GraalInternalError(ex);
+        }
+    }
+
+    @Fold
+    private static Class getAESCryptClass() {
+        return AESCryptSubstitutions.AESCryptClass;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    static void encrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
+        Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset));
+        if (getAESCryptClass().isInstance(embeddedCipher)) {
+            Word kAddr = Word.fromObject(embeddedCipher).readWord(Word.unsigned(AESCryptSubstitutions.kOffset)).add(arrayBaseOffset(Kind.Byte));
+            Word rAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(rOffset)).add(arrayBaseOffset(Kind.Byte));
+            Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset);
+            Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset);
+            EncryptAESCryptStubCall.call(inAddr, outAddr, kAddr, rAddr, inLength);
+        } else {
+            encrypt(rcvr, in, inOffset, inLength, out, outOffset);
+        }
+    }
+
+    @MethodSubstitution(isStatic = false)
+    static void decrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
+        Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset));
+        if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
+            Word kAddr = Word.fromObject(embeddedCipher).readWord(Word.unsigned(AESCryptSubstitutions.kOffset)).add(arrayBaseOffset(Kind.Byte));
+            Word rAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(rOffset)).add(arrayBaseOffset(Kind.Byte));
+            Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset);
+            Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset);
+            DecryptAESCryptStubCall.call(inAddr, outAddr, kAddr, rAddr, inLength);
+        } else {
+            decrypt(rcvr, in, inOffset, inLength, out, outOffset);
+        }
+    }
+
+    public static class EncryptAESCryptStubCall extends FixedWithNextNode implements LIRGenLowerable {
+
+        @Input private final ValueNode in;
+        @Input private final ValueNode out;
+        @Input private final ValueNode key;
+        @Input private final ValueNode r;
+        @Input private final ValueNode inLength;
+
+        public static final Descriptor ENCRYPT = new Descriptor("encrypt", false, void.class, Word.class, Word.class, Word.class, Word.class, int.class);
+
+        public EncryptAESCryptStubCall(ValueNode in, ValueNode out, ValueNode key, ValueNode r, ValueNode inLength) {
+            super(StampFactory.forVoid());
+            this.in = in;
+            this.out = out;
+            this.key = key;
+            this.r = r;
+            this.inLength = inLength;
+        }
+
+        @Override
+        public void generate(LIRGenerator gen) {
+            RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(ENCRYPT);
+            gen.emitCall(stub, stub.getCallingConvention(), false, gen.operand(in), gen.operand(out), gen.operand(key), gen.operand(r), gen.operand(inLength));
+        }
+
+        @NodeIntrinsic
+        public static native void call(Word in, Word out, Word key, Word r, int inLength);
+    }
+
+    public static class DecryptAESCryptStubCall extends FixedWithNextNode implements LIRGenLowerable {
+
+        @Input private final ValueNode in;
+        @Input private final ValueNode out;
+        @Input private final ValueNode key;
+        @Input private final ValueNode r;
+        @Input private final ValueNode inLength;
+
+        public static final Descriptor DECRYPT = new Descriptor("decrypt", false, void.class, Word.class, Word.class, Word.class, Word.class, int.class);
+
+        public DecryptAESCryptStubCall(ValueNode in, ValueNode out, ValueNode key, ValueNode r, ValueNode inLength) {
+            super(StampFactory.forVoid());
+            this.in = in;
+            this.out = out;
+            this.key = key;
+            this.r = r;
+            this.inLength = inLength;
+        }
+
+        @Override
+        public void generate(LIRGenerator gen) {
+            RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(DECRYPT);
+            gen.emitCall(stub, stub.getCallingConvention(), false, gen.operand(in), gen.operand(out), gen.operand(key), gen.operand(r), gen.operand(inLength));
+        }
+
+        @NodeIntrinsic
+        public static native void call(Word in, Word out, Word key, Word r, int inLength);
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSnippets.java	Wed Jan 16 09:05:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2012, 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.snippets;
-
-import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
-import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
-
-import java.lang.reflect.*;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.snippets.*;
-import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution;
-import com.oracle.graal.word.*;
-
-/**
- * Snippets for {@link java.lang.Class} methods.
- */
-@ClassSubstitution(java.lang.Class.class)
-public class ClassSnippets implements SnippetsInterface {
-    @MethodSubstitution(isStatic = false)
-    public static int getModifiers(final Class<?> thisObj) {
-        Word klass = loadWordFromObject(thisObj, klassOffset());
-        if (klass == Word.zero()) {
-            // Class for primitive type
-            return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC;
-        } else {
-            return klass.readInt(klassModifierFlagsOffset());
-        }
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static boolean isInterface(final Class<?> thisObj) {
-        Word klass = loadWordFromObject(thisObj, klassOffset());
-        if (klass == Word.zero()) {
-            return false;
-        } else {
-            int accessFlags = klass.readInt(klassAccessFlagsOffset());
-            return (accessFlags & Modifier.INTERFACE) != 0;
-        }
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static boolean isArray(final Class<?> thisObj) {
-        Word klass = loadWordFromObject(thisObj, klassOffset());
-        if (klass == Word.zero()) {
-            return false;
-        } else {
-            int layoutHelper = klass.readInt(klassLayoutHelperOffset());
-            return (layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0;
-        }
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static boolean isPrimitive(final Class<?> thisObj) {
-        Word klass = loadWordFromObject(thisObj, klassOffset());
-        return klass == Word.zero();
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static Class<?> getSuperclass(final Class<?> thisObj) {
-        Word klass = loadWordFromObject(thisObj, klassOffset());
-        if (klass != Word.zero()) {
-            int accessFlags = klass.readInt(klassAccessFlagsOffset());
-            if ((accessFlags & Modifier.INTERFACE) == 0) {
-                int layoutHelper = klass.readInt(klassLayoutHelperOffset());
-                if ((layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0) {
-                    return Object.class;
-                } else {
-                    Word superKlass = klass.readWord(klassSuperKlassOffset());
-                    if (superKlass == Word.zero()) {
-                        return null;
-                    } else {
-                        return unsafeCast(superKlass.readObject(classMirrorOffset()), Class.class, true, true);
-                    }
-                }
-            }
-        }
-        return null;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static Class<?> getComponentType(final Class<?> thisObj) {
-        Word klass = loadWordFromObject(thisObj, klassOffset());
-        if (klass != Word.zero()) {
-            int layoutHelper = klass.readInt(klassLayoutHelperOffset());
-            if ((layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0) {
-                return unsafeCast(klass.readObject(arrayKlassComponentMirrorOffset()), Class.class, true, true);
-            }
-        }
-        return null;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static boolean isInstance(final Class<?> thisObj, Object obj) {
-        return !thisObj.isPrimitive() && MaterializeNode.isInstance(thisObj, obj);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSubstitutions.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2012, 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.snippets;
+
+import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
+import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.snippets.*;
+import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution;
+import com.oracle.graal.word.*;
+
+/**
+ * Substitutions for {@link java.lang.Class} methods.
+ */
+@ClassSubstitution(java.lang.Class.class)
+public class ClassSubstitutions {
+    @MethodSubstitution(isStatic = false)
+    public static int getModifiers(final Class<?> thisObj) {
+        Word klass = loadWordFromObject(thisObj, klassOffset());
+        if (klass == Word.zero()) {
+            // Class for primitive type
+            return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC;
+        } else {
+            return klass.readInt(klassModifierFlagsOffset());
+        }
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static boolean isInterface(final Class<?> thisObj) {
+        Word klass = loadWordFromObject(thisObj, klassOffset());
+        if (klass == Word.zero()) {
+            return false;
+        } else {
+            int accessFlags = klass.readInt(klassAccessFlagsOffset());
+            return (accessFlags & Modifier.INTERFACE) != 0;
+        }
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static boolean isArray(final Class<?> thisObj) {
+        Word klass = loadWordFromObject(thisObj, klassOffset());
+        if (klass == Word.zero()) {
+            return false;
+        } else {
+            int layoutHelper = klass.readInt(klassLayoutHelperOffset());
+            return (layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0;
+        }
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static boolean isPrimitive(final Class<?> thisObj) {
+        Word klass = loadWordFromObject(thisObj, klassOffset());
+        return klass == Word.zero();
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static Class<?> getSuperclass(final Class<?> thisObj) {
+        Word klass = loadWordFromObject(thisObj, klassOffset());
+        if (klass != Word.zero()) {
+            int accessFlags = klass.readInt(klassAccessFlagsOffset());
+            if ((accessFlags & Modifier.INTERFACE) == 0) {
+                int layoutHelper = klass.readInt(klassLayoutHelperOffset());
+                if ((layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0) {
+                    return Object.class;
+                } else {
+                    Word superKlass = klass.readWord(klassSuperKlassOffset());
+                    if (superKlass == Word.zero()) {
+                        return null;
+                    } else {
+                        return unsafeCast(superKlass.readObject(classMirrorOffset()), Class.class, true, true);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static Class<?> getComponentType(final Class<?> thisObj) {
+        Word klass = loadWordFromObject(thisObj, klassOffset());
+        if (klass != Word.zero()) {
+            int layoutHelper = klass.readInt(klassLayoutHelperOffset());
+            if ((layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0) {
+                return unsafeCast(klass.readObject(arrayKlassComponentMirrorOffset()), Class.class, true, true);
+            }
+        }
+        return null;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static boolean isInstance(final Class<?> thisObj, Object obj) {
+        return !thisObj.isPrimitive() && MaterializeNode.isInstance(thisObj, obj);
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java	Wed Jan 16 09:08:24 2013 +0100
@@ -26,6 +26,7 @@
 import static com.oracle.graal.hotspot.snippets.CheckCastSnippets.Templates.*;
 import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
 import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*;
+import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -66,11 +67,13 @@
                     @Parameter("falseValue") Object falseValue,
                     @ConstantParameter("checkNull") boolean checkNull) {
         if (checkNull && object == null) {
+            probability(0.01);
             isNull.inc();
             return falseValue;
         }
         Word objectHub = loadHub(object);
         if (objectHub != exactHub) {
+            probability(0.75);
             exactMiss.inc();
             return falseValue;
         }
@@ -90,11 +93,13 @@
                     @ConstantParameter("checkNull") boolean checkNull,
                     @ConstantParameter("superCheckOffset") int superCheckOffset) {
         if (checkNull && object == null) {
+            probability(0.01);
             isNull.inc();
             return falseValue;
         }
         Word objectHub = loadHub(object);
         if (objectHub.readWord(superCheckOffset) != hub) {
+            probability(0.45);
             displayMiss.inc();
             return falseValue;
         }
@@ -114,6 +119,7 @@
                     @VarargsParameter("hints") Word[] hints,
                     @ConstantParameter("checkNull") boolean checkNull) {
         if (checkNull && object == null) {
+            probability(0.01);
             isNull.inc();
             return falseValue;
         }
@@ -123,6 +129,7 @@
         for (int i = 0; i < hints.length; i++) {
             Word hintHub = hints[i];
             if (hintHub == objectHub) {
+                probability(0.01);
                 hintsHit.inc();
                 return trueValue;
             }
@@ -151,6 +158,7 @@
         int length = secondarySupers.readInt(metaspaceArrayLengthOffset());
         for (int i = 0; i < length; i++) {
             if (t == loadWordElement(secondarySupers, i)) {
+                probability(0.01);
                 s.writeWord(secondarySuperCacheOffset(), t);
                 secondariesHit.inc();
                 return true;
@@ -171,6 +179,7 @@
                     @Parameter("falseValue") Object falseValue,
                     @ConstantParameter("checkNull") boolean checkNull) {
         if (checkNull && object == null) {
+            probability(0.01);
             isNull.inc();
             return falseValue;
         }
@@ -240,7 +249,7 @@
         }
     }
 
-    private static final SnippetCounter.Group counters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("Checkcast") : null;
+    private static final SnippetCounter.Group counters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("InstanceOf") : null;
     private static final SnippetCounter hintsHit = new SnippetCounter(counters, "hintsHit", "hit a hint type");
     private static final SnippetCounter exactHit = new SnippetCounter(counters, "exactHit", "exact type test succeeded");
     private static final SnippetCounter exactMiss = new SnippetCounter(counters, "exactMiss", "exact type test failed");
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java	Wed Jan 16 09:08:24 2013 +0100
@@ -30,6 +30,7 @@
 import static com.oracle.graal.snippets.SnippetTemplate.*;
 import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*;
 import static com.oracle.graal.snippets.nodes.ExplodeLoopNode.*;
+import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -64,6 +65,7 @@
         Word newTop = top.add(size);
         // this check might lead to problems if the TLAB is within 16GB of the address space end (checked in c++ code)
         if (newTop.belowOrEqual(end)) {
+            probability(0.99);
             thread.writeWord(threadTlabTopOffset(), newTop);
             return top;
         }
@@ -84,6 +86,7 @@
             new_stub.inc();
             result = NewInstanceStubCall.call(hub);
         } else {
+            probability(0.99);
             if (locked) {
                 formatObject(hub, size, memory, thread().or(biasedLockPattern()), fillContents);
             } else {
@@ -117,6 +120,7 @@
             newarray_stub.inc();
             result = NewArrayStubCall.call(hub, length);
         } else {
+            probability(0.99);
             newarray_loopInit.inc();
             formatArray(hub, allocationSize, length, headerSize, memory, prototypeMarkWord, fillContents);
             result = memory.toObject();
@@ -140,6 +144,7 @@
             // This handles both negative array sizes and very large array sizes
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
+        probability(0.99);
         int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
         Word memory = TLABAllocateNode.allocateVariableSize(allocationSize);
         return InitializeArrayNode.initialize(memory, length, allocationSize, type, true, false);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSnippets.java	Wed Jan 16 09:05:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2012, 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.snippets;
-
-import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
-import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
-
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.snippets.*;
-import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution;
-import com.oracle.graal.word.*;
-
-/**
- * Snippets for {@link java.lang.Object} methods.
- */
-@ClassSubstitution(java.lang.Object.class)
-public class ObjectSnippets implements SnippetsInterface {
-    @MethodSubstitution(isStatic = false)
-    public static Class<?> getClass(final Object thisObj) {
-        Word hub = loadHub(thisObj);
-        return unsafeCast(hub.readFinalObject(Word.signed(classMirrorOffset())), Class.class, true, true);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static int hashCode(final Object thisObj) {
-        Word mark = loadWordFromObject(thisObj, markOffset());
-
-        // this code is independent from biased locking (although it does not look that way)
-        final Word biasedLock = mark.and(biasedLockMaskInPlace());
-        if (biasedLock == Word.unsigned(unlockedMask())) {
-            int hash = (int) mark.unsignedShiftRight(identityHashCodeShift()).rawValue();
-            if (hash != uninitializedIdentityHashCodeValue()) {
-                return hash;
-            }
-        }
-
-        return IdentityHashCodeStubCall.call(thisObj);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012, 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.snippets;
+
+import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
+import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
+import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*;
+
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.snippets.*;
+import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution;
+import com.oracle.graal.word.*;
+
+/**
+ * Substitutions for {@link java.lang.Object} methods.
+ */
+@ClassSubstitution(java.lang.Object.class)
+public class ObjectSubstitutions {
+
+    @MethodSubstitution(isStatic = false)
+    public static Class< ? > getClass(final Object thisObj) {
+        Word hub = loadHub(thisObj);
+        return unsafeCast(hub.readFinalObject(Word.signed(classMirrorOffset())), Class.class, true, true);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static int hashCode(final Object thisObj) {
+        Word mark = loadWordFromObject(thisObj, markOffset());
+
+        // this code is independent from biased locking (although it does not look that way)
+        final Word biasedLock = mark.and(biasedLockMaskInPlace());
+        if (biasedLock == Word.unsigned(unlockedMask())) {
+            probability(0.99);
+            int hash = (int) mark.unsignedShiftRight(identityHashCodeShift()).rawValue();
+            if (hash != uninitializedIdentityHashCodeValue()) {
+                probability(0.99);
+                return hash;
+            }
+        }
+
+        return IdentityHashCodeStubCall.call(thisObj);
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/SystemSnippets.java	Wed Jan 16 09:05:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * 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.snippets;
-
-import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
-
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.graph.Node.ConstantNodeParameter;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.snippets.*;
-import com.oracle.graal.word.*;
-
-/**
- * Snippets for {@link java.lang.System} methods.
- */
-@ClassSubstitution(java.lang.System.class)
-public class SystemSnippets implements SnippetsInterface {
-
-    public static final Descriptor JAVA_TIME_MILLIS = new Descriptor("javaTimeMillis", false, long.class);
-    public static final Descriptor JAVA_TIME_NANOS = new Descriptor("javaTimeNanos", false, long.class);
-
-    public static long currentTimeMillis() {
-        return callLong(JAVA_TIME_MILLIS);
-    }
-
-    public static long nanoTime() {
-        return callLong(JAVA_TIME_NANOS);
-    }
-
-    public static int identityHashCode(Object x) {
-        if (x == null) {
-            return 0;
-        }
-
-        Word mark = loadWordFromObject(x, markOffset());
-
-        // this code is independent from biased locking (although it does not look that way)
-        final Word biasedLock = mark.and(biasedLockMaskInPlace());
-        if (biasedLock == Word.unsigned(unlockedMask())) {
-            int hash = (int) mark.unsignedShiftRight(identityHashCodeShift()).rawValue();
-            if (hash != uninitializedIdentityHashCodeValue()) {
-                return hash;
-            }
-        }
-
-        return IdentityHashCodeStubCall.call(x);
-    }
-
-    @NodeIntrinsic(value = RuntimeCallNode.class, setStampFromReturnType = true)
-    public static native long callLong(@ConstantNodeParameter Descriptor descriptor);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/SystemSubstitutions.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,81 @@
+/*
+ * 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.snippets;
+
+import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
+import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.snippets.*;
+import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution;
+import com.oracle.graal.word.*;
+
+/**
+ * Substitutions for {@link java.lang.System} methods.
+ */
+@ClassSubstitution(java.lang.System.class)
+public class SystemSubstitutions {
+
+    public static final Descriptor JAVA_TIME_MILLIS = new Descriptor("javaTimeMillis", false, long.class);
+    public static final Descriptor JAVA_TIME_NANOS = new Descriptor("javaTimeNanos", false, long.class);
+
+    @MethodSubstitution
+    public static long currentTimeMillis() {
+        return callLong(JAVA_TIME_MILLIS);
+    }
+
+    @MethodSubstitution
+    public static long nanoTime() {
+        return callLong(JAVA_TIME_NANOS);
+    }
+
+    @MethodSubstitution
+    public static int identityHashCode(Object x) {
+        if (x == null) {
+            probability(0.01);
+            return 0;
+        }
+
+        Word mark = loadWordFromObject(x, markOffset());
+
+        // this code is independent from biased locking (although it does not look that way)
+        final Word biasedLock = mark.and(biasedLockMaskInPlace());
+        if (biasedLock == Word.unsigned(unlockedMask())) {
+            probability(0.99);
+            int hash = (int) mark.unsignedShiftRight(identityHashCodeShift()).rawValue();
+            if (hash != uninitializedIdentityHashCodeValue()) {
+                probability(0.99);
+                return hash;
+            }
+        }
+
+        return IdentityHashCodeStubCall.call(x);
+    }
+
+    @NodeIntrinsic(value = RuntimeCallNode.class, setStampFromReturnType = true)
+    public static native long callLong(@ConstantNodeParameter Descriptor descriptor);
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSnippets.java	Wed Jan 16 09:05:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2012, 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.snippets;
-
-import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
-
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.snippets.*;
-import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution;
-import com.oracle.graal.word.*;
-
-/**
- * Snippets for {@link java.lang.Thread} methods.
- */
-@ClassSubstitution(java.lang.Thread.class)
-public class ThreadSnippets implements SnippetsInterface {
-    public static Thread currentThread() {
-        return CurrentThread.get();
-    }
-
-    @MethodSubstitution(isStatic = false)
-    private static boolean isInterrupted(final Thread thisObject, boolean clearInterrupted) {
-        Word rawThread = HotSpotCurrentRawThreadNode.get();
-        Thread thread = (Thread) rawThread.readObject(threadObjectOffset());
-        if (thisObject == thread) {
-            Word osThread = rawThread.readWord(osThreadOffset());
-            boolean interrupted = osThread.readInt(osThreadInterruptedOffset()) != 0;
-            if (!interrupted || !clearInterrupted) {
-                return interrupted;
-            }
-        }
-
-        return ThreadIsInterruptedStubCall.call(thisObject, clearInterrupted) != 0;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSubstitutions.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2012, 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.snippets;
+
+import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
+
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.snippets.*;
+import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution;
+import com.oracle.graal.word.*;
+
+/**
+ * Substitutions for {@link java.lang.Thread} methods.
+ */
+@ClassSubstitution(java.lang.Thread.class)
+public class ThreadSubstitutions {
+
+    @MethodSubstitution
+    public static Thread currentThread() {
+        return CurrentThread.get();
+    }
+
+    @MethodSubstitution(isStatic = false)
+    private static boolean isInterrupted(final Thread thisObject, boolean clearInterrupted) {
+        Word rawThread = HotSpotCurrentRawThreadNode.get();
+        Thread thread = (Thread) rawThread.readObject(threadObjectOffset());
+        if (thisObject == thread) {
+            Word osThread = rawThread.readWord(osThreadOffset());
+            boolean interrupted = osThread.readInt(osThreadInterruptedOffset()) != 0;
+            if (!interrupted || !clearInterrupted) {
+                return interrupted;
+            }
+        }
+
+        return ThreadIsInterruptedStubCall.call(thisObject, clearInterrupted) != 0;
+    }
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Jan 16 09:08:24 2013 +0100
@@ -409,7 +409,7 @@
 
     }
 
-    private void genArithmeticOp(Kind result, int opcode, boolean canTrap) {
+    private void genArithmeticOp(Kind result, int opcode) {
         ValueNode y = frameState.pop(result);
         ValueNode x = frameState.pop(result);
         boolean isStrictFP = isStrict(method.getModifiers());
@@ -427,21 +427,30 @@
             case LMUL: v = new IntegerMulNode(result, x, y); break;
             case FMUL:
             case DMUL: v = new FloatMulNode(result, x, y, isStrictFP); break;
-            case IDIV:
-            case LDIV: v = new IntegerDivNode(result, x, y); break;
             case FDIV:
             case DDIV: v = new FloatDivNode(result, x, y, isStrictFP); break;
-            case IREM:
-            case LREM: v = new IntegerRemNode(result, x, y); break;
             case FREM:
             case DREM: v = new FloatRemNode(result, x, y, isStrictFP); break;
             default:
                 throw new GraalInternalError("should not reach");
         }
         ValueNode result1 = append(currentGraph.unique(v));
-        if (canTrap) {
-            append(currentGraph.add(new ValueAnchorNode(result1)));
+        frameState.push(result, result1);
+    }
+
+    private void genIntegerDivOp(Kind result, int opcode) {
+        ValueNode y = frameState.pop(result);
+        ValueNode x = frameState.pop(result);
+        FixedWithNextNode v;
+        switch(opcode){
+            case IDIV:
+            case LDIV: v = new IntegerDivNode(result, x, y); break;
+            case IREM:
+            case LREM: v = new IntegerRemNode(result, x, y); break;
+            default:
+                throw new GraalInternalError("should not reach");
         }
+        ValueNode result1 = append(currentGraph.add(v));
         frameState.push(result, result1);
     }
 
@@ -1680,24 +1689,24 @@
             case SWAP           : stackOp(opcode); break;
             case IADD           : // fall through
             case ISUB           : // fall through
-            case IMUL           : genArithmeticOp(Kind.Int, opcode, false); break;
+            case IMUL           : genArithmeticOp(Kind.Int, opcode); break;
             case IDIV           : // fall through
-            case IREM           : genArithmeticOp(Kind.Int, opcode, true); break;
+            case IREM           : genIntegerDivOp(Kind.Int, opcode); break;
             case LADD           : // fall through
             case LSUB           : // fall through
-            case LMUL           : genArithmeticOp(Kind.Long, opcode, false); break;
+            case LMUL           : genArithmeticOp(Kind.Long, opcode); break;
             case LDIV           : // fall through
-            case LREM           : genArithmeticOp(Kind.Long, opcode, true); break;
+            case LREM           : genIntegerDivOp(Kind.Long, opcode); break;
             case FADD           : // fall through
             case FSUB           : // fall through
             case FMUL           : // fall through
             case FDIV           : // fall through
-            case FREM           : genArithmeticOp(Kind.Float, opcode, false); break;
+            case FREM           : genArithmeticOp(Kind.Float, opcode); break;
             case DADD           : // fall through
             case DSUB           : // fall through
             case DMUL           : // fall through
             case DDIV           : // fall through
-            case DREM           : genArithmeticOp(Kind.Double, opcode, false); break;
+            case DREM           : genArithmeticOp(Kind.Double, opcode); break;
             case INEG           : genNegateOp(Kind.Int); break;
             case LNEG           : genNegateOp(Kind.Long); break;
             case FNEG           : genNegateOp(Kind.Float); break;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Wed Jan 16 09:08:24 2013 +0100
@@ -35,8 +35,8 @@
 import com.oracle.graal.lir.asm.*;
 
 public enum AMD64Arithmetic {
-    IADD, ISUB, IMUL, IDIV, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR,
-    LADD, LSUB, LMUL, LDIV, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR,
+    IADD, ISUB, IMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR,
+    LADD, LSUB, LMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR,
     FADD, FSUB, FMUL, FDIV, FAND, FOR, FXOR,
     DADD, DSUB, DMUL, DDIV, DAND, DOR, DXOR,
     INEG, LNEG,
@@ -195,6 +195,39 @@
         }
     }
 
+    public static class DivRemOp extends AMD64LIRInstruction {
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def protected Value divResult;
+        @Def protected Value remResult;
+        @Use protected Value x;
+        @Alive protected Value y;
+        @State protected LIRFrameState state;
+
+        public DivRemOp(AMD64Arithmetic opcode, Value x, Value y, LIRFrameState state) {
+            this.opcode = opcode;
+            this.divResult = AMD64.rax.asValue(x.getKind());
+            this.remResult = AMD64.rdx.asValue(x.getKind());
+            this.x = x;
+            this.y = y;
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+            emit(tasm, masm, opcode, null, y, state);
+        }
+
+        @Override
+        protected void verify() {
+            super.verify();
+            // left input in rax, right input in any register but rax and rdx, result quotient in rax, result remainder in rdx
+            assert asRegister(x) == AMD64.rax;
+            assert differentRegisters(y, AMD64.rax.asValue(), AMD64.rdx.asValue());
+            verifyKind(opcode, divResult, x, y);
+            verifyKind(opcode, remResult, x, y);
+        }
+    }
+
     public static class DivOp extends AMD64LIRInstruction {
         @Opcode private final AMD64Arithmetic opcode;
         @Def protected Value result;
@@ -310,6 +343,7 @@
                 case MOV_F2I: masm.movdl(asIntReg(dst), asFloatReg(src)); break;
                 case MOV_D2L: masm.movdq(asLongReg(dst), asDoubleReg(src)); break;
 
+                case IDIVREM:
                 case IDIV:
                 case IREM:
                     masm.cdql();
@@ -317,24 +351,12 @@
                     masm.idivl(asRegister(src));
                     break;
 
+                case LDIVREM:
                 case LDIV:
                 case LREM:
-                    Label continuation = new Label();
-                    if (opcode == LDIV) {
-                        // check for special case of Long.MIN_VALUE / -1
-                        Label normalCase = new Label();
-                        masm.movq(AMD64.rdx, java.lang.Long.MIN_VALUE);
-                        masm.cmpq(AMD64.rax, AMD64.rdx);
-                        masm.jcc(ConditionFlag.notEqual, normalCase);
-                        masm.cmpq(asRegister(src), -1);
-                        masm.jcc(ConditionFlag.equal, continuation);
-                        masm.bind(normalCase);
-                    }
-
                     masm.cdqq();
                     exceptionOffset = masm.codeBuffer.position();
                     masm.idivq(asRegister(src));
-                    masm.bind(continuation);
                     break;
 
                 case IUDIV:
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Wed Jan 16 09:08:24 2013 +0100
@@ -113,22 +113,6 @@
             }
 
             assert lir.lir(block).get(0) instanceof StandardOp.LabelOp : "block must start with label";
-            if (block.numberOfPreds() > 1) {
-                assert lir.lir(block).get(0) instanceof StandardOp.PhiLabelOp : "phi mapping required for multiple predecessors";
-                Value[] phiDefinitions = ((StandardOp.PhiLabelOp) lir.lir(block).get(0)).getPhiDefinitions();
-                if (!beforeRegisterAllocation) {
-                    assert phiDefinitions.length == 0;
-                }
-                for (Block pred : block.getPredecessors()) {
-                    assert pred.numberOfSux() == 1;
-                    LIRInstruction last = lir.lir(pred).get(lir.lir(pred).size() - 1);
-                    assert last instanceof StandardOp.PhiJumpOp : "phi mapping required for multiple successors";
-                    Value[] phiUses = ((StandardOp.PhiJumpOp) last).getPhiInputs();
-                    if (!beforeRegisterAllocation) {
-                        assert phiUses.length == 0;
-                    }
-                }
-            }
 
             if (block.numberOfSux() > 0) {
                 LIRInstruction last = lir.lir(block).get(lir.lir(block).size() - 1);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Wed Jan 16 09:08:24 2013 +0100
@@ -60,7 +60,7 @@
         @Override
         public void emitCode(TargetMethodAssembler tasm) {
             if (align) {
-                tasm.asm.align(tasm.target.wordSize);
+                tasm.asm.align(tasm.target.wordSize * 2);
             }
             tasm.asm.bind(label);
         }
@@ -70,23 +70,6 @@
         }
     }
 
-    public static class PhiLabelOp extends LabelOp {
-        @Def({REG, STACK}) protected Value[] phiDefinitions;
-
-        public PhiLabelOp(Label label, boolean align, Value[] phiDefinitions) {
-            super(label, align);
-            this.phiDefinitions = phiDefinitions;
-        }
-
-        public void markResolved() {
-            phiDefinitions = EMPTY;
-        }
-
-        public Value[] getPhiDefinitions() {
-            return phiDefinitions;
-        }
-    }
-
     /**
      * LIR operation that is an unconditional jump to {@link #destination()}.
      * When the LIR is constructed, the last operation of every block must implement this interface. After
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Wed Jan 16 09:08:24 2013 +0100
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.loop;
 
-import com.oracle.graal.loop.InductionVariable.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.loop.InductionVariable.Direction;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 
 public class CountedLoopInfo {
     private final LoopEx loop;
@@ -41,7 +41,8 @@
 
     public ValueNode maxTripCountNode() {
         //TODO (gd) stuarte and respect oneOff
-        return IntegerArithmeticNode.div(IntegerArithmeticNode.sub(end, iv.initNode()), iv.strideNode());
+        throw GraalInternalError.unimplemented("division is a fixed node that needs to be inserted into the control flow");
+        // return IntegerArithmeticNode.div(IntegerArithmeticNode.sub(end, iv.initNode()), iv.strideNode());
     }
 
     public boolean isConstantMaxTripCount() {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Wed Jan 16 09:08:24 2013 +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/FixedNode.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java	Wed Jan 16 09:08:24 2013 +0100
@@ -41,6 +41,7 @@
     }
 
     public void setProbability(double probability) {
+        assert probability >= 0 : String.format("Invalid argument %f, because the probability of a node must not be negative.", probability);
         this.probability = probability;
         assert !Double.isNaN(probability);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Wed Jan 16 09:08:24 2013 +0100
@@ -121,6 +121,10 @@
         return this;
     }
 
+    public void setTakenProbability(double prob) {
+        takenProbability = prob;
+    }
+
     @Override
     public double probability(BeginNode successor) {
         return successor == trueSuccessor ? takenProbability : 1 - takenProbability;
@@ -358,10 +362,13 @@
                 PhiNode oldPhi = (PhiNode) oldMerge.usages().first();
                 PhiNode newPhi = graph().add(new PhiNode(oldPhi.stamp(), newMerge));
 
+                double probability = 0.0;
                 for (EndNode end : ends) {
                     newPhi.addInput(phiValues.get(end));
                     newMerge.addForwardEnd(end);
+                    probability += end.probability();
                 }
+                newMerge.setProbability(probability);
 
                 FrameState stateAfter = oldMerge.stateAfter();
                 if (stateAfter != null) {
@@ -425,6 +432,7 @@
         originalFalseSuccessor.prepareDelete();
 
         FixedNode next = merge.next();
+        FrameState state = merge.stateAfter();
         merge.setNext(null);
         setTrueSuccessor(null);
         setFalseSuccessor(null);
@@ -435,6 +443,9 @@
         merge.safeDelete();
         trueEnd.safeDelete();
         falseEnd.safeDelete();
+        if (state != null) {
+            tool.removeIfUnused(state);
+        }
         tool.addToWorkList(next);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Wed Jan 16 09:08:24 2013 +0100
@@ -109,6 +109,8 @@
         Map<Object, Object> debugProperties = super.getDebugProperties(map);
         if (callTarget instanceof MethodCallTargetNode && methodCallTarget().targetMethod() != null) {
             debugProperties.put("targetMethod", methodCallTarget().targetMethod());
+        } else if (callTarget instanceof AbstractCallTargetNode) {
+            debugProperties.put("targetMethod", ((AbstractCallTargetNode) callTarget).target());
         }
         return debugProperties;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Wed Jan 16 09:08:24 2013 +0100
@@ -59,7 +59,7 @@
     @Override
     public boolean inferStamp() {
         if (object().objectStamp().alwaysNull() && objectStamp().nonNull()) {
-            // a null value flowing into a nonNull PiNode can happen should be guarded by a type/isNull guard, but the
+            // a null value flowing into a nonNull PiNode should be guarded by a type/isNull guard, but the
             // compiler might see this situation before the branch is deleted
             return false;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FixedBinaryNode.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,49 @@
+/*
+ * 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.nodes.calc;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+
+@NodeInfo(shortName = "/")
+public class FixedBinaryNode extends FixedWithNextNode {
+
+    @Input private ValueNode x;
+    @Input private ValueNode y;
+
+    public ValueNode x() {
+        return x;
+    }
+
+    public ValueNode y() {
+        return y;
+    }
+
+    public FixedBinaryNode(Kind kind, ValueNode x, ValueNode y) {
+        super(StampFactory.forKind(kind));
+        this.x = x;
+        this.y = y;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Wed Jan 16 09:08:24 2013 +0100
@@ -72,17 +72,4 @@
                 throw ValueNodeUtil.shouldNotReachHere();
         }
     }
-
-    public static IntegerDivNode div(ValueNode v1, ValueNode v2) {
-        assert v1.kind() == v2.kind() && v1.graph() == v2.graph();
-        Graph graph = v1.graph();
-        switch(v1.kind()) {
-            case Int:
-                return graph.unique(new IntegerDivNode(Kind.Int, v1, v2));
-            case Long:
-                return graph.unique(new IntegerDivNode(Kind.Long, v1, v2));
-            default:
-                throw ValueNodeUtil.shouldNotReachHere();
-        }
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Wed Jan 16 09:08:24 2013 +0100
@@ -30,7 +30,7 @@
 import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "/")
-public final class IntegerDivNode extends IntegerArithmeticNode implements Canonicalizable, LIRLowerable {
+public class IntegerDivNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable {
 
     public IntegerDivNode(Kind kind, ValueNode x, ValueNode y) {
         super(kind, x, y);
@@ -87,10 +87,27 @@
                 return shift;
             }
         }
+
+        // Convert the expression ((a - a % b) / b) into (a / b).
+        if (x() instanceof IntegerSubNode) {
+            IntegerSubNode integerSubNode = (IntegerSubNode) x();
+            if (integerSubNode.y() instanceof IntegerRemNode) {
+                IntegerRemNode integerRemNode = (IntegerRemNode) integerSubNode.y();
+                if (integerSubNode.kind() == this.kind() && integerRemNode.kind() == this.kind() && integerSubNode.x() == integerRemNode.x() && this.y() == integerRemNode.y()) {
+                    return graph().add(new IntegerDivNode(kind(), integerSubNode.x(), this.y()));
+                }
+            }
+        }
+
         return this;
     }
 
     @Override
+    public void lower(LoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
         gen.setResult(this, gen.emitDiv(gen.operand(x()), gen.operand(y())));
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Wed Jan 16 09:08:24 2013 +0100
@@ -29,7 +29,7 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "%")
-public final class IntegerRemNode extends IntegerArithmeticNode implements Canonicalizable, LIRLowerable {
+public class IntegerRemNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable {
 
     public IntegerRemNode(Kind kind, ValueNode x, ValueNode y) {
         super(kind, x, y);
@@ -60,6 +60,11 @@
     }
 
     @Override
+    public void lower(LoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
         gen.setResult(this, gen.emitRem(gen.operand(x()), gen.operand(y())));
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Wed Jan 16 09:08:24 2013 +0100
@@ -29,7 +29,7 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "|/|")
-public final class UnsignedDivNode extends IntegerArithmeticNode implements Canonicalizable, LIRLowerable {
+public class UnsignedDivNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable {
 
     public UnsignedDivNode(Kind kind, ValueNode x, ValueNode y) {
         super(kind, x, y);
@@ -61,6 +61,11 @@
     }
 
     @Override
+    public void lower(LoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
         gen.setResult(this, gen.emitUDiv(gen.operand(x()), gen.operand(y())));
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Wed Jan 16 09:08:24 2013 +0100
@@ -29,7 +29,7 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "|%|")
-public final class UnsignedRemNode extends IntegerArithmeticNode implements Canonicalizable, LIRLowerable {
+public class UnsignedRemNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable {
 
     public UnsignedRemNode(Kind kind, ValueNode x, ValueNode y) {
         super(kind, x, y);
@@ -60,7 +60,12 @@
     }
 
     @Override
+    public void lower(LoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
-        gen.setResult(this, gen.emitRem(gen.operand(x()), gen.operand(y())));
+        gen.setResult(this, gen.emitURem(gen.operand(x()), gen.operand(y())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Wed Jan 16 09:08:24 2013 +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/extended/UnsafeCastNode.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Wed Jan 16 09:08:24 2013 +0100
@@ -50,6 +50,19 @@
     }
 
     @Override
+    public boolean inferStamp() {
+        if (kind() != Kind.Object || object().kind() != Kind.Object) {
+            return false;
+        }
+        if (object().objectStamp().alwaysNull() && objectStamp().nonNull()) {
+            // a null value flowing into a nonNull UnsafeCastNode should be guarded by a type/isNull guard, but the
+            // compiler might see this situation before the branch is deleted
+            return false;
+        }
+        return updateStamp(stamp().join(object().stamp()));
+    }
+
+    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (kind() != object.kind()) {
             return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Wed Jan 16 09:08:24 2013 +0100
@@ -59,11 +59,10 @@
 
     @Override
     public boolean inferStamp() {
-        if (object().stamp().nonNull() && !stamp().nonNull()) {
-            setStamp(StampFactory.declaredNonNull(type));
-            return true;
+        if (object().objectStamp().alwaysNull() && objectStamp().nonNull()) {
+            return false;
         }
-        return super.inferStamp();
+        return updateStamp(stamp().join(object().stamp()));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Wed Jan 16 09:08:24 2013 +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/spi/CanonicalizerTool.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/CanonicalizerTool.java	Wed Jan 16 09:08:24 2013 +0100
@@ -24,10 +24,12 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 
 
 public interface CanonicalizerTool {
     TargetDescription target();
     Assumptions assumptions();
     MetaAccessProvider runtime();
+    void removeIfUnused(Node node);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/ObjectStamp.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/ObjectStamp.java	Wed Jan 16 09:08:24 2013 +0100
@@ -128,7 +128,7 @@
     }
 
     @Override
-    public Stamp join(Stamp otherStamp) {
+    public ObjectStamp join(Stamp otherStamp) {
         if (this == otherStamp) {
             return this;
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Wed Jan 16 09:08:24 2013 +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	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Wed Jan 16 09:08:24 2013 +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<>();
     }
@@ -127,7 +134,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 +175,19 @@
         return false;
     }
 
-    public static boolean tryCanonicalize(final Node node, final StructuredGraph graph, final SimplifierTool tool) {
+    public boolean tryCanonicalize(final Node 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 +206,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 +223,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
@@ -316,5 +341,10 @@
         public void addToWorkList(Node node) {
             nodeWorkSet.addAgain(node);
         }
+
+        @Override
+        public void removeIfUnused(Node node) {
+            tryKillUnused(node);
+        }
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java	Wed Jan 16 09:08:24 2013 +0100
@@ -72,6 +72,9 @@
     private void correctLoopFrequencies(Loop loop, double parentFrequency, BitSet visitedBlocks) {
         LoopBeginNode loopBegin = ((LoopBeginNode) loop.header.getBeginNode());
         double frequency = parentFrequency * loopBegin.loopFrequency();
+        if (frequency < 1) {
+            frequency = 1;
+        }
         for (Loop child : loop.children) {
             correctLoopFrequencies(child, frequency, visitedBlocks);
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Wed Jan 16 09:08:24 2013 +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;
@@ -91,7 +94,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	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Wed Jan 16 09:08:24 2013 +0100
@@ -888,7 +888,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();
 
@@ -917,7 +917,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;
@@ -1028,6 +1028,8 @@
 
         invoke.node().replaceAtUsages(null);
         GraphUtil.killCFG(invoke.node());
+
+        return duplicates;
     }
 
     public static void receiverNullCheck(Invoke invoke) {
@@ -1041,7 +1043,8 @@
     }
 
     public static boolean canIntrinsify(ResolvedJavaMethod target) {
-        return getIntrinsicGraph(target) != null;
+        StructuredGraph intrinsicGraph = getIntrinsicGraph(target);
+        return intrinsicGraph != null;
     }
 
     public static StructuredGraph getIntrinsicGraph(ResolvedJavaMethod target) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Wed Jan 16 09:08:24 2013 +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	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Wed Jan 16 09:08:24 2013 +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.phases/src/com/oracle/graal/phases/GraalOptions.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Wed Jan 16 09:08:24 2013 +0100
@@ -123,6 +123,7 @@
 
     // Debug settings:
     public static boolean Debug                              = true;
+    public static boolean DebugSnippets                      = false;
     public static boolean PerThreadDebugValues               = ____;
     public static boolean SummarizeDebugValues               = ____;
     public static boolean SummarizePerPhase                  = ____;
@@ -210,6 +211,7 @@
     public static boolean IntrinsifyThreadMethods            = true;
     public static boolean IntrinsifyUnsafeMethods            = true;
     public static boolean IntrinsifyMathMethods              = true;
+    public static boolean IntrinsifyAESMethods               = true;
 
     /**
      * Counts the various paths taken through snippets.
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Wed Jan 16 09:08:24 2013 +0100
@@ -27,27 +27,13 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
-public class GraphOrder implements Iterable<Node> {
+public final class GraphOrder implements Iterable<Node> {
 
     private final ArrayList<Node> nodes = new ArrayList<>();
 
     private GraphOrder() {
     }
 
-    public GraphOrder(Graph graph) {
-        NodeBitMap visited = graph.createNodeBitMap();
-
-        for (ReturnNode node : graph.getNodes(ReturnNode.class)) {
-            visitForward(visited, node);
-        }
-        for (UnwindNode node : graph.getNodes(UnwindNode.class)) {
-            visitForward(visited, node);
-        }
-        for (DeoptimizeNode node : graph.getNodes(DeoptimizeNode.class)) {
-            visitForward(visited, node);
-        }
-    }
-
     public static GraphOrder forwardGraph(Graph graph) {
         GraphOrder result = new GraphOrder();
 
@@ -92,6 +78,12 @@
             for (Node input : node.inputs()) {
                 visitForward(visited, input);
             }
+            if (node instanceof LoopBeginNode) {
+                LoopBeginNode loopBegin = (LoopBeginNode) node;
+                for (LoopEndNode loopEnd : loopBegin.loopEnds()) {
+                    visitForward(visited, loopEnd);
+                }
+            }
             nodes.add(node);
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/DebugEnvironment.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,48 @@
+/*
+ * 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.printer;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.graal.compiler.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.phases.*;
+
+
+public class DebugEnvironment {
+
+    public static void initialize(PrintStream log) {
+        Debug.enable();
+        List<DebugDumpHandler> dumpHandlers = new ArrayList<>();
+        dumpHandlers.add(new GraphPrinterDumpHandler());
+        if (GraalOptions.PrintCFG) {
+            if (GraalOptions.PrintBinaryGraphs) {
+                TTY.println("CFG dumping slows down PrintBinaryGraphs: use -G:-PrintCFG to disable it");
+            }
+            dumpHandlers.add(new CFGPrinterObserver());
+        }
+        GraalDebugConfig hotspotDebugConfig = new GraalDebugConfig(GraalOptions.Log, GraalOptions.Meter, GraalOptions.Time, GraalOptions.Dump, GraalOptions.MethodFilter, log, dumpHandlers);
+        Debug.setConfig(hotspotDebugConfig);
+    }
+}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/ClassSubstitution.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/ClassSubstitution.java	Wed Jan 16 09:08:24 2013 +0100
@@ -24,31 +24,61 @@
 
 import java.lang.annotation.*;
 
+import com.oracle.graal.api.meta.*;
+
 /**
- * Denotes a class that substitutes methods of another specified class with snippets.
+ * Denotes a class that substitutes methods of another specified class.
+ * The substitute methods are exactly those annotated by {@link MethodSubstitution}.
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.TYPE)
 public @interface ClassSubstitution {
 
-    Class<?> value();
+    /**
+     * Specifies the original class.
+     * <p>
+     * If the default value is specified for this element, then a non-default
+     * value must be given for the {@link #className()} element.
+      */
+    Class<?> value() default ClassSubstitution.class;
 
     /**
-     * Used to map a substitute method to an original method where the default mapping
-     * of name and signature is not possible due to name clashes with final methods in
-     * {@link Object} or signature types that are not public.
+     * Specifies the original class.
+     * <p>
+     * This method is provided for cases where the original class
+     * is not accessible (according to Java language access control rules).
+     * <p>
+     * If the default value is specified for this element, then a non-default
+     * value must be given for the {@link #value()} element.
+     */
+    String className() default "";
+
+    /**
+     * Denotes a substitute method. A substitute method can call the original/substituted
+     * method by making a recursive call to itself.
      */
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.METHOD)
     public @interface MethodSubstitution {
         /**
-         * Get the name of the original method.
+         * Gets the name of the original method.
+         * <p>
+         * If the default value is specified for this element, then the
+         * name of the original method is same as the substitute method.
          */
         String value() default "";
 
         /**
-         * Determine if the substituted method is static.
+         * Determines if the original method is static.
          */
         boolean isStatic() default true;
+
+        /**
+         * Gets the {@linkplain Signature#getMethodDescriptor() signature} of the original method.
+         * <p>
+         * If the default value is specified for this element, then the
+         * signature of the original method is the same as the substitute method.
+         */
+        String signature() default "";
     }
 }
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/DoubleSnippets.java	Wed Jan 16 09:05:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * 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.snippets;
-
-import com.oracle.graal.nodes.calc.*;
-
-/**
- * Snippets for {@link java.lang.Double} methods.
- */
-@ClassSubstitution(java.lang.Double.class)
-public class DoubleSnippets implements SnippetsInterface {
-
-    private static final long NAN_RAW_LONG_BITS = Double.doubleToRawLongBits(Double.NaN);
-
-    public static long doubleToRawLongBits(double value) {
-        @JavacBug(id = 6995200)
-        Long result = ConvertNode.convert(ConvertNode.Op.MOV_D2L, value);
-        return result;
-    }
-
-    // TODO This method is not necessary, since the JDK method does exactly this
-    public static long doubleToLongBits(double value) {
-        if (value != value) {
-            return NAN_RAW_LONG_BITS;
-        } else {
-            return doubleToRawLongBits(value);
-        }
-    }
-
-    public static double longBitsToDouble(long bits) {
-        @JavacBug(id = 6995200)
-        Double result = ConvertNode.convert(ConvertNode.Op.MOV_L2D, bits);
-        return result;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/DoubleSubstitutions.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,59 @@
+/*
+ * 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.snippets;
+
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.snippets.ClassSubstitution.*;
+
+/**
+ * Substitutions for {@link java.lang.Double} methods.
+ */
+@ClassSubstitution(java.lang.Double.class)
+public class DoubleSubstitutions {
+
+    private static final long NAN_RAW_LONG_BITS = Double.doubleToRawLongBits(Double.NaN);
+
+    @MethodSubstitution
+    public static long doubleToRawLongBits(double value) {
+        @JavacBug(id = 6995200)
+        Long result = ConvertNode.convert(ConvertNode.Op.MOV_D2L, value);
+        return result;
+    }
+
+    // TODO This method is not necessary, since the JDK method does exactly this
+    @MethodSubstitution
+    public static long doubleToLongBits(double value) {
+        if (value != value) {
+            return NAN_RAW_LONG_BITS;
+        } else {
+            return doubleToRawLongBits(value);
+        }
+    }
+
+    @MethodSubstitution
+    public static double longBitsToDouble(long bits) {
+        @JavacBug(id = 6995200)
+        Double result = ConvertNode.convert(ConvertNode.Op.MOV_L2D, bits);
+        return result;
+    }
+}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/FloatSnippets.java	Wed Jan 16 09:05:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * 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.snippets;
-
-import com.oracle.graal.nodes.calc.*;
-
-/**
- * Snippets for {@link java.lang.Float} methods.
- */
-@ClassSubstitution(java.lang.Float.class)
-public class FloatSnippets implements SnippetsInterface {
-
-    private static final int NAN_RAW_INT_BITS = Float.floatToRawIntBits(Float.NaN);
-
-    public static int floatToRawIntBits(float value) {
-        @JavacBug(id = 6995200)
-        Integer result = ConvertNode.convert(ConvertNode.Op.MOV_F2I, value);
-        return result;
-    }
-
-    // TODO This method is not necessary, since the JDK method does exactly this
-    public static int floatToIntBits(float value) {
-        if (value != value) {
-            return NAN_RAW_INT_BITS;
-        } else {
-            return floatToRawIntBits(value);
-        }
-    }
-
-    public static float intBitsToFloat(int bits) {
-        @JavacBug(id = 6995200)
-        Float result = ConvertNode.convert(ConvertNode.Op.MOV_I2F, bits);
-        return result;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/FloatSubstitutions.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,59 @@
+/*
+ * 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.snippets;
+
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.snippets.ClassSubstitution.*;
+
+/**
+ * Substitutions for {@link java.lang.Float} methods.
+ */
+@ClassSubstitution(java.lang.Float.class)
+public class FloatSubstitutions {
+
+    private static final int NAN_RAW_INT_BITS = Float.floatToRawIntBits(Float.NaN);
+
+    @MethodSubstitution
+    public static int floatToRawIntBits(float value) {
+        @JavacBug(id = 6995200)
+        Integer result = ConvertNode.convert(ConvertNode.Op.MOV_F2I, value);
+        return result;
+    }
+
+    // TODO This method is not necessary, since the JDK method does exactly this
+    @MethodSubstitution
+    public static int floatToIntBits(float value) {
+        if (value != value) {
+            return NAN_RAW_INT_BITS;
+        } else {
+            return floatToRawIntBits(value);
+        }
+    }
+
+    @MethodSubstitution
+    public static float intBitsToFloat(int bits) {
+        @JavacBug(id = 6995200)
+        Float result = ConvertNode.convert(ConvertNode.Op.MOV_I2F, bits);
+        return result;
+    }
+}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/GraalIntrinsics.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/GraalIntrinsics.java	Wed Jan 16 09:08:24 2013 +0100
@@ -30,13 +30,13 @@
 public class GraalIntrinsics {
     public static void installIntrinsics(SnippetInstaller installer) {
         if (GraalOptions.Intrinsify) {
-            installer.install(MathSnippetsX86.class);
-            installer.install(DoubleSnippets.class);
-            installer.install(FloatSnippets.class);
-            installer.install(NodeClassSnippets.class);
-            installer.install(LongSnippets.class);
-            installer.install(IntegerSnippets.class);
-            installer.install(UnsignedMathSnippets.class);
+            installer.installSubstitutions(MathSubstitutionsX86.class);
+            installer.installSubstitutions(DoubleSubstitutions.class);
+            installer.installSubstitutions(FloatSubstitutions.class);
+            installer.installSubstitutions(NodeClassSubstitutions.class);
+            installer.installSubstitutions(LongSubstitutions.class);
+            installer.installSubstitutions(IntegerSubstitutions.class);
+            installer.installSubstitutions(UnsignedMathSubstitutions.class);
         }
     }
 }
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/IntegerSnippets.java	Wed Jan 16 09:05:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, 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.snippets;
-
-import com.oracle.graal.snippets.nodes.*;
-
-@ClassSubstitution(Integer.class)
-public class IntegerSnippets implements SnippetsInterface{
-
-    public static int reverseBytes(int i) {
-        return ReverseBytesNode.reverse(i);
-    }
-
-    public static int numberOfLeadingZeros(int i) {
-        if (i == 0) {
-            return 32;
-        }
-        return 31 - BitScanReverseNode.scan(i);
-    }
-
-    public static int numberOfTrailingZeros(int i) {
-        if (i == 0) {
-            return 32;
-        }
-        return BitScanForwardNode.scan(i);
-    }
-
-    public static int bitCount(int i) {
-        return BitCountNode.bitCount(i);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/IntegerSubstitutions.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012, 2012, 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.snippets;
+
+import com.oracle.graal.snippets.ClassSubstitution.*;
+import com.oracle.graal.snippets.nodes.*;
+
+@ClassSubstitution(Integer.class)
+public class IntegerSubstitutions {
+
+    @MethodSubstitution
+    public static int reverseBytes(int i) {
+        return ReverseBytesNode.reverse(i);
+    }
+
+    @MethodSubstitution
+    public static int numberOfLeadingZeros(int i) {
+        if (i == 0) {
+            return 32;
+        }
+        return 31 - BitScanReverseNode.scan(i);
+    }
+
+    @MethodSubstitution
+    public static int numberOfTrailingZeros(int i) {
+        if (i == 0) {
+            return 32;
+        }
+        return BitScanForwardNode.scan(i);
+    }
+
+    @MethodSubstitution
+    public static int bitCount(int i) {
+        return BitCountNode.bitCount(i);
+    }
+}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/LongSnippets.java	Wed Jan 16 09:05:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, 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.snippets;
-
-import com.oracle.graal.snippets.nodes.*;
-
-@ClassSubstitution(Long.class)
-public class LongSnippets implements SnippetsInterface{
-
-    public static long reverseBytes(long i) {
-        return ReverseBytesNode.reverse(i);
-    }
-
-    public static int numberOfLeadingZeros(long i) {
-        if (i == 0) {
-            return 64;
-        }
-        return 63 - BitScanReverseNode.scan(i);
-    }
-
-    public static int numberOfTrailingZeros(long i) {
-        if (i == 0) {
-            return 64;
-        }
-        return BitScanForwardNode.scan(i);
-    }
-
-    public static int bitCount(long i) {
-        return BitCountNode.bitCount(i);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/LongSubstitutions.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012, 2012, 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.snippets;
+
+import com.oracle.graal.snippets.ClassSubstitution.*;
+import com.oracle.graal.snippets.nodes.*;
+
+@ClassSubstitution(Long.class)
+public class LongSubstitutions {
+
+    @MethodSubstitution
+    public static long reverseBytes(long i) {
+        return ReverseBytesNode.reverse(i);
+    }
+
+    @MethodSubstitution
+    public static int numberOfLeadingZeros(long i) {
+        if (i == 0) {
+            return 64;
+        }
+        return 63 - BitScanReverseNode.scan(i);
+    }
+
+    @MethodSubstitution
+    public static int numberOfTrailingZeros(long i) {
+        if (i == 0) {
+            return 64;
+        }
+        return BitScanForwardNode.scan(i);
+    }
+
+    @MethodSubstitution
+    public static int bitCount(long i) {
+        return BitCountNode.bitCount(i);
+    }
+}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/MathSnippetsX86.java	Wed Jan 16 09:05:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * 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.snippets;
-
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.graph.Node.ConstantNodeParameter;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.snippets.nodes.*;
-import com.oracle.graal.snippets.nodes.MathIntrinsicNode.Operation;
-
-/**
- * Snippets for {@link java.lang.Math} methods.
- */
-@ClassSubstitution(java.lang.Math.class)
-public class MathSnippetsX86 implements SnippetsInterface {
-
-    private static final double PI_4 = 0.7853981633974483;
-
-    public static double abs(double x) {
-        return MathIntrinsicNode.compute(x, Operation.ABS);
-    }
-
-    public static double sqrt(double x) {
-        return MathIntrinsicNode.compute(x, Operation.SQRT);
-    }
-
-    public static double log(double x) {
-        return MathIntrinsicNode.compute(x, Operation.LOG);
-    }
-
-    public static double log10(double x) {
-        return MathIntrinsicNode.compute(x, Operation.LOG10);
-    }
-
-    // NOTE on snippets below:
-    //   Math.sin(), .cos() and .tan() guarantee a value within 1 ULP of the
-    //   exact result, but x87 trigonometric FPU instructions are only that
-    //   accurate within [-pi/4, pi/4]. Examine the passed value and provide
-    //   a slow path for inputs outside of that interval.
-
-    public static double sin(double x) {
-        if (abs(x) < PI_4) {
-            return MathIntrinsicNode.compute(x, Operation.SIN);
-        } else {
-            return callDouble(ARITHMETIC_SIN, x);
-        }
-    }
-
-    public static double cos(double x) {
-        if (abs(x) < PI_4) {
-            return MathIntrinsicNode.compute(x, Operation.COS);
-        } else {
-            return callDouble(ARITHMETIC_COS, x);
-        }
-    }
-
-    public static double tan(double x) {
-        if (abs(x) < PI_4) {
-            return MathIntrinsicNode.compute(x, Operation.TAN);
-        } else {
-            return callDouble(ARITHMETIC_TAN, x);
-        }
-    }
-
-    public static final Descriptor ARITHMETIC_SIN = new Descriptor("arithmeticSin", false, double.class, double.class);
-    public static final Descriptor ARITHMETIC_COS = new Descriptor("arithmeticCos", false, double.class, double.class);
-    public static final Descriptor ARITHMETIC_TAN = new Descriptor("arithmeticTan", false, double.class, double.class);
-
-    @NodeIntrinsic(value = RuntimeCallNode.class, setStampFromReturnType = true)
-    public static native double callDouble(@ConstantNodeParameter Descriptor descriptor, double value);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/MathSubstitutionsX86.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,100 @@
+/*
+ * 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.snippets;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution;
+import com.oracle.graal.snippets.nodes.*;
+import com.oracle.graal.snippets.nodes.MathIntrinsicNode.Operation;
+
+/**
+ * Substitutions for {@link java.lang.Math} methods.
+ */
+@ClassSubstitution(java.lang.Math.class)
+public class MathSubstitutionsX86 {
+
+    private static final double PI_4 = 0.7853981633974483;
+
+    @MethodSubstitution
+    public static double abs(double x) {
+        return MathIntrinsicNode.compute(x, Operation.ABS);
+    }
+
+    @MethodSubstitution
+    public static double sqrt(double x) {
+        return MathIntrinsicNode.compute(x, Operation.SQRT);
+    }
+
+    @MethodSubstitution
+    public static double log(double x) {
+        return MathIntrinsicNode.compute(x, Operation.LOG);
+    }
+
+    @MethodSubstitution
+    public static double log10(double x) {
+        return MathIntrinsicNode.compute(x, Operation.LOG10);
+    }
+
+    // NOTE on snippets below:
+    //   Math.sin(), .cos() and .tan() guarantee a value within 1 ULP of the
+    //   exact result, but x87 trigonometric FPU instructions are only that
+    //   accurate within [-pi/4, pi/4]. Examine the passed value and provide
+    //   a slow path for inputs outside of that interval.
+
+    @MethodSubstitution
+    public static double sin(double x) {
+        if (abs(x) < PI_4) {
+            return MathIntrinsicNode.compute(x, Operation.SIN);
+        } else {
+            return callDouble(ARITHMETIC_SIN, x);
+        }
+    }
+
+    @MethodSubstitution
+    public static double cos(double x) {
+        if (abs(x) < PI_4) {
+            return MathIntrinsicNode.compute(x, Operation.COS);
+        } else {
+            return callDouble(ARITHMETIC_COS, x);
+        }
+    }
+
+    @MethodSubstitution
+    public static double tan(double x) {
+        if (abs(x) < PI_4) {
+            return MathIntrinsicNode.compute(x, Operation.TAN);
+        } else {
+            return callDouble(ARITHMETIC_TAN, x);
+        }
+    }
+
+    public static final Descriptor ARITHMETIC_SIN = new Descriptor("arithmeticSin", false, double.class, double.class);
+    public static final Descriptor ARITHMETIC_COS = new Descriptor("arithmeticCos", false, double.class, double.class);
+    public static final Descriptor ARITHMETIC_TAN = new Descriptor("arithmeticTan", false, double.class, double.class);
+
+    @NodeIntrinsic(value = RuntimeCallNode.class, setStampFromReturnType = true)
+    public static native double callDouble(@ConstantNodeParameter Descriptor descriptor, double value);
+}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/NodeClassSnippets.java	Wed Jan 16 09:05:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * 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.snippets;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * Snippets for improving the performance of some critical methods in {@link NodeClass} methods.
- * These snippets improve the performance by forcing the relevant methods to be inlined
- * (intrinsification being a special form of inlining) and removing a checked cast.
- * The latter cannot be done directly in Java code as {@link UnsafeCastNode}
- * is not available to the project containing {@link NodeClass}.
- */
-@SuppressWarnings("unused")
-@ClassSubstitution(NodeClass.class)
-public class NodeClassSnippets implements SnippetsInterface {
-
-    private static Node getNode(Node node, long offset) {
-        return UnsafeCastNode.unsafeCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), Node.class, false, false);
-    }
-
-    private static NodeList getNodeList(Node node, long offset) {
-        return UnsafeCastNode.unsafeCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), NodeList.class, false, false);
-    }
-
-    private static void putNode(Node node, long offset, Node value) {
-        UnsafeStoreNode.store(node, 0, offset, value, Kind.Object);
-    }
-
-    private static void putNodeList(Node node, long offset, NodeList value) {
-        UnsafeStoreNode.store(node, 0, offset, value, Kind.Object);
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/NodeClassSubstitutions.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,60 @@
+/*
+ * 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.snippets;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.snippets.ClassSubstitution.*;
+
+/**
+ * Substitutions for improving the performance of some critical methods in {@link NodeClass} methods.
+ * These substitutions improve the performance by forcing the relevant methods to be inlined
+ * (intrinsification being a special form of inlining) and removing a checked cast.
+ * The latter cannot be done directly in Java code as {@link UnsafeCastNode}
+ * is not available to the project containing {@link NodeClass}.
+ */
+@ClassSubstitution(NodeClass.class)
+public class NodeClassSubstitutions {
+
+    @MethodSubstitution
+    private static Node getNode(Node node, long offset) {
+        return UnsafeCastNode.unsafeCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), Node.class, false, false);
+    }
+
+    @MethodSubstitution
+    private static NodeList getNodeList(Node node, long offset) {
+        return UnsafeCastNode.unsafeCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), NodeList.class, false, false);
+    }
+
+    @MethodSubstitution
+    private static void putNode(Node node, long offset, Node value) {
+        UnsafeStoreNode.store(node, 0, offset, value, Kind.Object);
+    }
+
+    @MethodSubstitution
+    private static void putNodeList(Node node, long offset, NodeList value) {
+        UnsafeStoreNode.store(node, 0, offset, value, Kind.Object);
+    }
+
+}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java	Wed Jan 16 09:08:24 2013 +0100
@@ -22,15 +22,18 @@
  */
 package com.oracle.graal.snippets;
 
+import static com.oracle.graal.api.meta.MetaUtil.*;
+
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
 
+import sun.misc.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -44,7 +47,8 @@
 import com.oracle.graal.word.phases.*;
 
 /**
- * Utility for snippet {@linkplain #install(Class) installation}.
+ * Utility for {@linkplain #installSnippets(Class) snippet} and
+ * {@linkplain #installSubstitutions(Class) substitution} installation.
  */
 public class SnippetInstaller {
 
@@ -52,6 +56,7 @@
     private final TargetDescription target;
     private final Assumptions assumptions;
     private final BoxingMethodPool pool;
+    private final Thread owner;
 
     /**
      * A graph cache used by this installer to avoid using the compiler
@@ -67,26 +72,15 @@
         this.assumptions = assumptions;
         this.pool = new BoxingMethodPool(runtime);
         this.graphCache = new HashMap<>();
+        this.owner = Thread.currentThread();
     }
 
     /**
      * Finds all the snippet methods in a given class, builds a graph for them and
      * installs the graph with the key value of {@code Graph.class} in the
      * {@linkplain ResolvedJavaMethod#getCompilerStorage() compiler storage} of each method.
-     * <p>
-     * If {@code snippetsHolder} is annotated with {@link ClassSubstitution}, then all
-     * methods in the class are snippets. Otherwise, the snippets are those methods
-     * annotated with {@link Snippet}.
      */
-    public void install(Class<? extends SnippetsInterface> snippetsHolder) {
-        if (snippetsHolder.isAnnotationPresent(ClassSubstitution.class)) {
-            installSubstitutions(snippetsHolder, snippetsHolder.getAnnotation(ClassSubstitution.class).value());
-        } else {
-            installSnippets(snippetsHolder);
-        }
-    }
-
-    private void installSnippets(Class< ? extends SnippetsInterface> clazz) {
+    public void installSnippets(Class< ? extends SnippetsInterface> clazz) {
         for (Method method : clazz.getDeclaredMethods()) {
             if (method.getAnnotation(Snippet.class) != null) {
                 int modifiers = method.getModifiers();
@@ -102,43 +96,58 @@
         }
     }
 
-    private void installSubstitutions(Class< ? extends SnippetsInterface> clazz, Class<?> originalClazz) {
-        for (Method method : clazz.getDeclaredMethods()) {
-            if (method.getAnnotation(NodeIntrinsic.class) != null) {
+    /**
+     * Finds all the {@linkplain MethodSubstitution substitution} methods in a given class,
+     * builds a graph for them. If the original class is resolvable, then the
+     * graph is installed with the key value of {@code Graph.class} in the
+     * {@linkplain ResolvedJavaMethod#getCompilerStorage() compiler storage} of each original method.
+     */
+    public void installSubstitutions(Class<?> substitutions) {
+        assert owner == Thread.currentThread() : "substitution installation must be single threaded";
+        ClassSubstitution classSubstitution = substitutions.getAnnotation(ClassSubstitution.class);
+        for (Method substituteMethod : substitutions.getDeclaredMethods()) {
+            MethodSubstitution methodSubstitution = substituteMethod.getAnnotation(MethodSubstitution.class);
+            if (methodSubstitution == null) {
                 continue;
             }
-            try {
-                MethodSubstitution methodSubstitution = method.getAnnotation(MethodSubstitution.class);
-                String originalName = method.getName();
-                Class<?>[] originalParameters = method.getParameterTypes();
-                if (methodSubstitution != null) {
-                    if (!methodSubstitution.value().isEmpty()) {
-                        originalName = methodSubstitution.value();
-                    }
-                    if (!methodSubstitution.isStatic()) {
-                        assert originalParameters.length >= 1 : "must be a static method with the this object as its first parameter";
-                        Class<?>[] newParameters = new Class<?>[originalParameters.length - 1];
-                        System.arraycopy(originalParameters, 1, newParameters, 0, newParameters.length);
-                        originalParameters = newParameters;
-                    }
-                }
-                Method originalMethod = originalClazz.getDeclaredMethod(originalName, originalParameters);
-                if (!originalMethod.getReturnType().isAssignableFrom(method.getReturnType())) {
-                    throw new RuntimeException("Snippet has incompatible return type: " + method);
-                }
-                int modifiers = method.getModifiers();
-                if (!Modifier.isStatic(modifiers)) {
-                    throw new RuntimeException("Snippets must be static methods: " + method);
-                } else if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
-                    throw new RuntimeException("Snippet must not be abstract or native: " + method);
-                }
-                ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method);
-                StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet), true);
-                //System.out.println("snippet: " + graph);
-                runtime.lookupJavaMethod(originalMethod).getCompilerStorage().put(Graph.class, graph);
-            } catch (NoSuchMethodException e) {
-                throw new GraalInternalError("Could not resolve method in " + originalClazz + " to substitute with " + method, e);
+
+            int modifiers = substituteMethod.getModifiers();
+            if (!Modifier.isStatic(modifiers)) {
+                throw new RuntimeException("Substitution methods must be static: " + substituteMethod);
+            } else if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+                throw new RuntimeException("Substitution method must not be abstract or native: " + substituteMethod);
             }
+
+            String originalName = originalName(substituteMethod, methodSubstitution);
+            Class[] originalParameters = originalParameters(substituteMethod, methodSubstitution);
+            Method originalMethod = originalMethod(classSubstitution, originalName, originalParameters);
+            installSubstitution(originalMethod, substituteMethod);
+        }
+    }
+
+    // These fields are used to detect calls from the substitute method to the original method.
+    ResolvedJavaMethod substitute;
+    ResolvedJavaMethod original;
+    boolean substituteCallsOriginal;
+
+    /**
+     * Installs a method substitution.
+     *
+     * @param originalMethod a method being substituted
+     * @param substituteMethod the substitute method
+     */
+    protected void installSubstitution(Method originalMethod, Method substituteMethod) {
+        substitute = runtime.lookupJavaMethod(substituteMethod);
+        original = runtime.lookupJavaMethod(originalMethod);
+        try {
+            //System.out.println("substitution: " + MetaUtil.format("%H.%n(%p)", original) + " --> " + MetaUtil.format("%H.%n(%p)", substitute));
+            StructuredGraph graph = makeGraph(substitute, inliningPolicy(substitute), true);
+            Object oldValue = original.getCompilerStorage().put(Graph.class, graph);
+            assert oldValue == null;
+        } finally {
+            substitute = null;
+            original = null;
+            substituteCallsOriginal = false;
         }
     }
 
@@ -158,7 +167,7 @@
         }
     }
 
-    public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy, final boolean isSubstitutionSnippet) {
+    public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy, final boolean isSubstitution) {
         return Debug.scope("BuildSnippetGraph", new Object[] {method}, new Callable<StructuredGraph>() {
             @Override
             public StructuredGraph call() throws Exception {
@@ -166,8 +175,8 @@
 
                 new SnippetIntrinsificationPhase(runtime, pool, SnippetTemplate.hasConstantParameter(method)).apply(graph);
 
-                if (isSubstitutionSnippet) {
-                    // TODO (ds) remove the constraint of only processing substitution snippets
+                if (isSubstitution && !substituteCallsOriginal) {
+                    // TODO (ds) remove the constraint of only processing substitutions
                     // once issues with the arraycopy snippets have been resolved
                     new SnippetFrameStateCleanupPhase().apply(graph);
                     new DeadCodeEliminationPhase().apply(graph);
@@ -208,14 +217,29 @@
         for (Invoke invoke : graph.getInvokes()) {
             MethodCallTargetNode callTarget = invoke.methodCallTarget();
             ResolvedJavaMethod callee = callTarget.targetMethod();
-            if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) && policy.shouldInline(callee, method)) {
-                StructuredGraph targetGraph = parseGraph(callee, policy);
-                InliningUtil.inline(invoke, targetGraph, true);
+            if (callee == substitute) {
+                final StructuredGraph originalGraph = new StructuredGraph(original);
+                new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(originalGraph);
+                InliningUtil.inline(invoke, originalGraph, true);
+
+                // TODO the inlined frame states still show the call from the substitute to the original.
+                // If this poses a problem, a phase should added to fix up these frame states.
+
                 Debug.dump(graph, "after inlining %s", callee);
                 if (GraalOptions.OptCanonicalizer) {
-                    new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph);
                     new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
                 }
+                substituteCallsOriginal = true;
+            } else {
+                if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) && policy.shouldInline(callee, method)) {
+                    StructuredGraph targetGraph = parseGraph(callee, policy);
+                    InliningUtil.inline(invoke, targetGraph, true);
+                    Debug.dump(graph, "after inlining %s", callee);
+                    if (GraalOptions.OptCanonicalizer) {
+                        new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph);
+                        new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
+                    }
+                }
             }
         }
 
@@ -238,4 +262,65 @@
         }
         return graph;
     }
+
+    private static String originalName(Method substituteMethod, MethodSubstitution methodSubstitution) {
+        String name = substituteMethod.getName();
+        if (!methodSubstitution.value().isEmpty()) {
+            name = methodSubstitution.value();
+        }
+        return name;
+    }
+
+    private static Class resolveType(String className) {
+        try {
+            // Need to use launcher class path to handle classes
+            // that are not on the boot class path
+            ClassLoader cl = Launcher.getLauncher().getClassLoader();
+            return Class.forName(className, false, cl);
+        } catch (ClassNotFoundException e) {
+            throw new GraalInternalError("Could not resolve type " + className);
+        }
+    }
+
+    private static Class resolveType(JavaType type) {
+        JavaType base = type;
+        int dimensions = 0;
+        while (base.getComponentType() != null) {
+            base = base.getComponentType();
+            dimensions++;
+        }
+
+        Class baseClass = base.getKind() != Kind.Object ? base.getKind().toJavaClass() : resolveType(toJavaName(base));
+        return dimensions == 0 ? baseClass : Array.newInstance(baseClass, new int[dimensions]).getClass();
+    }
+
+    private Class[] originalParameters(Method substituteMethod, MethodSubstitution methodSubstitution) {
+        Class[] parameters;
+        if (methodSubstitution.signature().isEmpty()) {
+            parameters = substituteMethod.getParameterTypes();
+            if (!methodSubstitution.isStatic()) {
+                assert parameters.length > 0 : "must be a static method with the 'this' object as its first parameter";
+                parameters = Arrays.copyOfRange(parameters, 1, parameters.length);
+            }
+        } else {
+            Signature signature = runtime.parseMethodDescriptor(methodSubstitution.signature());
+            parameters = new Class[signature.getParameterCount(false)];
+            for (int i = 0; i < parameters.length; i++) {
+                parameters[i] = resolveType(signature.getParameterType(i, null));
+            }
+        }
+        return parameters;
+    }
+
+    private static Method originalMethod(ClassSubstitution classSubstitution, String name, Class[] parameters) {
+        Class<?> originalClass = classSubstitution.value();
+        if (originalClass == ClassSubstitution.class) {
+            originalClass = resolveType(classSubstitution.className());
+        }
+        try {
+            return originalClass.getDeclaredMethod(name, parameters);
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new GraalInternalError(e);
+        }
+    }
 }
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Wed Jan 16 09:08:24 2013 +0100
@@ -282,7 +282,7 @@
             new SnippetIntrinsificationPhase(runtime, new BoxingMethodPool(runtime), false).apply(snippetCopy);
             new WordTypeRewriterPhase(runtime, 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
@@ -340,7 +340,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.snippets/src/com/oracle/graal/snippets/UnsafeSnippets.java	Wed Jan 16 09:05:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,382 +0,0 @@
-/*
- * 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.snippets;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution;
-import com.oracle.graal.snippets.nodes.*;
-
-/**
- * Snippets for {@link sun.misc.Unsafe} methods.
- */
-@ClassSubstitution(sun.misc.Unsafe.class)
-public class UnsafeSnippets implements SnippetsInterface {
-    @MethodSubstitution(isStatic = false)
-    public static boolean compareAndSwapObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object expected, Object x) {
-        return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static boolean compareAndSwapInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int expected, int x) {
-        return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static boolean compareAndSwapLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long expected, long x) {
-        return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static Object getObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        return UnsafeLoadNode.load(o, 0, offset, Kind.Object);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static Object getObjectVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
-        Object result = getObject(thisObj, o, offset);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object x) {
-        UnsafeStoreNode.store(o, 0, offset, x, Kind.Object);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putObjectVolatile(final Object thisObj, Object o, long offset, Object x) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
-        putObject(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putOrderedObject(final Object thisObj, Object o, long offset, Object x) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
-        putObject(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static int getInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        Integer value = UnsafeLoadNode.load(o, 0, offset, Kind.Int);
-        return value;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static int getIntVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
-        int result = getInt(thisObj, o, offset);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int x) {
-        UnsafeStoreNode.store(o, 0, offset, x, Kind.Int);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putIntVolatile(final Object thisObj, Object o, long offset, int x) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
-        putInt(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putOrderedInt(final Object thisObj, Object o, long offset, int x) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
-        putInt(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static boolean getBoolean(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        @JavacBug(id = 6995200)
-        Boolean result = UnsafeLoadNode.load(o, 0, offset, Kind.Boolean);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static boolean getBooleanVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
-        boolean result = getBoolean(thisObj, o, offset);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putBoolean(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, boolean x) {
-        UnsafeStoreNode.store(o, 0, offset, x, Kind.Boolean);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putBooleanVolatile(final Object thisObj, Object o, long offset, boolean x) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
-        putBoolean(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static byte getByte(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        @JavacBug(id = 6995200)
-        Byte result = UnsafeLoadNode.load(o, 0, offset, Kind.Byte);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static byte getByteVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
-        byte result = getByte(thisObj, o, offset);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putByte(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, byte x) {
-        UnsafeStoreNode.store(o, 0, offset, x, Kind.Byte);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putByteVolatile(final Object thisObj, Object o, long offset, byte x) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
-        putByte(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static short getShort(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        @JavacBug(id = 6995200)
-        Short result = UnsafeLoadNode.load(o, 0, offset, Kind.Short);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static short getShortVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
-        short result = getShort(thisObj, o, offset);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putShort(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, short x) {
-        UnsafeStoreNode.store(o, 0, offset, x, Kind.Short);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putShortVolatile(final Object thisObj, Object o, long offset, short x) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
-        putShort(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static char getChar(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        @JavacBug(id = 6995200)
-        Character result = UnsafeLoadNode.load(o, 0, offset, Kind.Char);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static char getCharVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
-        char result = getChar(thisObj, o, offset);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putChar(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, char x) {
-        UnsafeStoreNode.store(o, 0, offset, x, Kind.Char);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putCharVolatile(final Object thisObj, Object o, long offset, char x) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
-        putChar(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static long getLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        @JavacBug(id = 6995200)
-        Long result = UnsafeLoadNode.load(o, 0, offset, Kind.Long);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static long getLongVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
-        long result = getLong(thisObj, o, offset);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long x) {
-        UnsafeStoreNode.store(o, 0, offset, x, Kind.Long);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putLongVolatile(final Object thisObj, Object o, long offset, long x) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
-        putLong(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putOrderedLong(final Object thisObj, Object o, long offset, long x) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
-        putLong(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static float getFloat(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        @JavacBug(id = 6995200)
-        Float result = UnsafeLoadNode.load(o, 0, offset, Kind.Float);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static float getFloatVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
-        float result = getFloat(thisObj, o, offset);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putFloat(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, float x) {
-        UnsafeStoreNode.store(o, 0, offset, x, Kind.Float);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putFloatVolatile(final Object thisObj, Object o, long offset, float x) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
-        putFloat(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static double getDouble(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        @JavacBug(id = 6995200)
-        Double result = UnsafeLoadNode.load(o, 0, offset, Kind.Double);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static double getDoubleVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
-        double result = getDouble(thisObj, o, offset);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putDouble(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, double x) {
-        UnsafeStoreNode.store(o, 0, offset, x, Kind.Double);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putDoubleVolatile(final Object thisObj, Object o, long offset, double x) {
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
-        putDouble(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putByte(@SuppressWarnings("unused") final Object thisObj, long address, byte value) {
-        DirectStoreNode.store(address, value);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putShort(@SuppressWarnings("unused") final Object thisObj, long address, short value) {
-        DirectStoreNode.store(address, value);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putChar(@SuppressWarnings("unused") final Object thisObj, long address, char value) {
-        DirectStoreNode.store(address, value);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putInt(@SuppressWarnings("unused") final Object thisObj, long address, int value) {
-        DirectStoreNode.store(address, value);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putLong(@SuppressWarnings("unused") final Object thisObj, long address, long value) {
-        DirectStoreNode.store(address, value);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putFloat(@SuppressWarnings("unused") final Object thisObj, long address, float value) {
-        DirectStoreNode.store(address, value);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putDouble(@SuppressWarnings("unused") final Object thisObj, long address, double value) {
-        DirectStoreNode.store(address, value);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static byte getByte(@SuppressWarnings("unused") final Object thisObj, long address) {
-        return DirectReadNode.read(address, Kind.Byte);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static short getShort(@SuppressWarnings("unused") final Object thisObj, long address) {
-        return DirectReadNode.read(address, Kind.Short);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static char getChar(@SuppressWarnings("unused") final Object thisObj, long address) {
-        return DirectReadNode.read(address, Kind.Char);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static int getInt(@SuppressWarnings("unused") final Object thisObj, long address) {
-        return DirectReadNode.read(address, Kind.Int);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static long getLong(@SuppressWarnings("unused") final Object thisObj, long address) {
-        return DirectReadNode.read(address, Kind.Long);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static float getFloat(@SuppressWarnings("unused") final Object thisObj, long address) {
-        return DirectReadNode.read(address, Kind.Float);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static double getDouble(@SuppressWarnings("unused") final Object thisObj, long address) {
-        return DirectReadNode.read(address, Kind.Double);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/UnsafeSubstitutions.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,382 @@
+/*
+ * 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.snippets;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution;
+import com.oracle.graal.snippets.nodes.*;
+
+/**
+ * Substitutions for {@link sun.misc.Unsafe} methods.
+ */
+@ClassSubstitution(sun.misc.Unsafe.class)
+public class UnsafeSubstitutions {
+    @MethodSubstitution(isStatic = false)
+    public static boolean compareAndSwapObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object expected, Object x) {
+        return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static boolean compareAndSwapInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int expected, int x) {
+        return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static boolean compareAndSwapLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long expected, long x) {
+        return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static Object getObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
+        return UnsafeLoadNode.load(o, 0, offset, Kind.Object);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static Object getObjectVolatile(final Object thisObj, Object o, long offset) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
+        Object result = getObject(thisObj, o, offset);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
+        return result;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object x) {
+        UnsafeStoreNode.store(o, 0, offset, x, Kind.Object);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putObjectVolatile(final Object thisObj, Object o, long offset, Object x) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
+        putObject(thisObj, o, offset, x);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putOrderedObject(final Object thisObj, Object o, long offset, Object x) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
+        putObject(thisObj, o, offset, x);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static int getInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
+        Integer value = UnsafeLoadNode.load(o, 0, offset, Kind.Int);
+        return value;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static int getIntVolatile(final Object thisObj, Object o, long offset) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
+        int result = getInt(thisObj, o, offset);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
+        return result;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int x) {
+        UnsafeStoreNode.store(o, 0, offset, x, Kind.Int);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putIntVolatile(final Object thisObj, Object o, long offset, int x) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
+        putInt(thisObj, o, offset, x);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putOrderedInt(final Object thisObj, Object o, long offset, int x) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
+        putInt(thisObj, o, offset, x);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static boolean getBoolean(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
+        @JavacBug(id = 6995200)
+        Boolean result = UnsafeLoadNode.load(o, 0, offset, Kind.Boolean);
+        return result;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static boolean getBooleanVolatile(final Object thisObj, Object o, long offset) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
+        boolean result = getBoolean(thisObj, o, offset);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
+        return result;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putBoolean(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, boolean x) {
+        UnsafeStoreNode.store(o, 0, offset, x, Kind.Boolean);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putBooleanVolatile(final Object thisObj, Object o, long offset, boolean x) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
+        putBoolean(thisObj, o, offset, x);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static byte getByte(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
+        @JavacBug(id = 6995200)
+        Byte result = UnsafeLoadNode.load(o, 0, offset, Kind.Byte);
+        return result;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static byte getByteVolatile(final Object thisObj, Object o, long offset) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
+        byte result = getByte(thisObj, o, offset);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
+        return result;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putByte(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, byte x) {
+        UnsafeStoreNode.store(o, 0, offset, x, Kind.Byte);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putByteVolatile(final Object thisObj, Object o, long offset, byte x) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
+        putByte(thisObj, o, offset, x);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static short getShort(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
+        @JavacBug(id = 6995200)
+        Short result = UnsafeLoadNode.load(o, 0, offset, Kind.Short);
+        return result;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static short getShortVolatile(final Object thisObj, Object o, long offset) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
+        short result = getShort(thisObj, o, offset);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
+        return result;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putShort(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, short x) {
+        UnsafeStoreNode.store(o, 0, offset, x, Kind.Short);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putShortVolatile(final Object thisObj, Object o, long offset, short x) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
+        putShort(thisObj, o, offset, x);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static char getChar(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
+        @JavacBug(id = 6995200)
+        Character result = UnsafeLoadNode.load(o, 0, offset, Kind.Char);
+        return result;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static char getCharVolatile(final Object thisObj, Object o, long offset) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
+        char result = getChar(thisObj, o, offset);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
+        return result;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putChar(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, char x) {
+        UnsafeStoreNode.store(o, 0, offset, x, Kind.Char);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putCharVolatile(final Object thisObj, Object o, long offset, char x) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
+        putChar(thisObj, o, offset, x);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static long getLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
+        @JavacBug(id = 6995200)
+        Long result = UnsafeLoadNode.load(o, 0, offset, Kind.Long);
+        return result;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static long getLongVolatile(final Object thisObj, Object o, long offset) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
+        long result = getLong(thisObj, o, offset);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
+        return result;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long x) {
+        UnsafeStoreNode.store(o, 0, offset, x, Kind.Long);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putLongVolatile(final Object thisObj, Object o, long offset, long x) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
+        putLong(thisObj, o, offset, x);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putOrderedLong(final Object thisObj, Object o, long offset, long x) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
+        putLong(thisObj, o, offset, x);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static float getFloat(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
+        @JavacBug(id = 6995200)
+        Float result = UnsafeLoadNode.load(o, 0, offset, Kind.Float);
+        return result;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static float getFloatVolatile(final Object thisObj, Object o, long offset) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
+        float result = getFloat(thisObj, o, offset);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
+        return result;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putFloat(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, float x) {
+        UnsafeStoreNode.store(o, 0, offset, x, Kind.Float);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putFloatVolatile(final Object thisObj, Object o, long offset, float x) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
+        putFloat(thisObj, o, offset, x);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static double getDouble(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
+        @JavacBug(id = 6995200)
+        Double result = UnsafeLoadNode.load(o, 0, offset, Kind.Double);
+        return result;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static double getDoubleVolatile(final Object thisObj, Object o, long offset) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ);
+        double result = getDouble(thisObj, o, offset);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ);
+        return result;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putDouble(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, double x) {
+        UnsafeStoreNode.store(o, 0, offset, x, Kind.Double);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putDoubleVolatile(final Object thisObj, Object o, long offset, double x) {
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE);
+        putDouble(thisObj, o, offset, x);
+        MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putByte(@SuppressWarnings("unused") final Object thisObj, long address, byte value) {
+        DirectStoreNode.store(address, value);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putShort(@SuppressWarnings("unused") final Object thisObj, long address, short value) {
+        DirectStoreNode.store(address, value);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putChar(@SuppressWarnings("unused") final Object thisObj, long address, char value) {
+        DirectStoreNode.store(address, value);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putInt(@SuppressWarnings("unused") final Object thisObj, long address, int value) {
+        DirectStoreNode.store(address, value);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putLong(@SuppressWarnings("unused") final Object thisObj, long address, long value) {
+        DirectStoreNode.store(address, value);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putFloat(@SuppressWarnings("unused") final Object thisObj, long address, float value) {
+        DirectStoreNode.store(address, value);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void putDouble(@SuppressWarnings("unused") final Object thisObj, long address, double value) {
+        DirectStoreNode.store(address, value);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static byte getByte(@SuppressWarnings("unused") final Object thisObj, long address) {
+        return DirectReadNode.read(address, Kind.Byte);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static short getShort(@SuppressWarnings("unused") final Object thisObj, long address) {
+        return DirectReadNode.read(address, Kind.Short);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static char getChar(@SuppressWarnings("unused") final Object thisObj, long address) {
+        return DirectReadNode.read(address, Kind.Char);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static int getInt(@SuppressWarnings("unused") final Object thisObj, long address) {
+        return DirectReadNode.read(address, Kind.Int);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static long getLong(@SuppressWarnings("unused") final Object thisObj, long address) {
+        return DirectReadNode.read(address, Kind.Long);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static float getFloat(@SuppressWarnings("unused") final Object thisObj, long address) {
+        return DirectReadNode.read(address, Kind.Float);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static double getDouble(@SuppressWarnings("unused") final Object thisObj, long address) {
+        return DirectReadNode.read(address, Kind.Double);
+    }
+}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/UnsignedMathSnippets.java	Wed Jan 16 09:05:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
-/*
- * 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.snippets;
-
-import static com.oracle.graal.nodes.MaterializeNode.*;
-import static com.oracle.graal.nodes.calc.Condition.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.nodes.calc.*;
-
-/**
- * Snippets for {@link UnsignedMath}.
- */
-@ClassSubstitution(UnsignedMath.class)
-public class UnsignedMathSnippets implements SnippetsInterface {
-
-    public static boolean aboveThan(int a, int b) {
-        return materialize(BT, b, a);
-    }
-
-    public static boolean aboveOrEqual(int a, int b) {
-        return !materialize(BT, a, b);
-    }
-
-    /**
-     * Unsigned comparison belowThan for two numbers.
-     */
-    public static boolean belowThan(int a, int b) {
-        return materialize(BT, a, b);
-    }
-
-    /**
-     * Unsigned comparison belowOrEqual for two numbers.
-     */
-    public static boolean belowOrEqual(int a, int b) {
-        return !materialize(BT, b, a);
-    }
-
-    /**
-     * Unsigned comparison aboveThan for two numbers.
-     */
-    public static boolean aboveThan(long a, long b) {
-        return materialize(BT, b, a);
-    }
-
-    /**
-     * Unsigned comparison aboveOrEqual for two numbers.
-     */
-    public static boolean aboveOrEqual(long a, long b) {
-        return !materialize(BT, a, b);
-    }
-
-    /**
-     * Unsigned comparison belowThan for two numbers.
-     */
-    public static boolean belowThan(long a, long b) {
-        return materialize(BT, a, b);
-    }
-
-    /**
-     * Unsigned comparison belowOrEqual for two numbers.
-     */
-    public static boolean belowOrEqual(long a, long b) {
-        return !materialize(BT, b, a);
-    }
-
-    /**
-     * Unsigned division for two numbers.
-     */
-    public static int divide(int a, int b) {
-        return unsignedDivide(Kind.Int, a, b);
-    }
-
-    /**
-     * Unsigned remainder for two numbers.
-     */
-    public static int remainder(int a, int b) {
-        return unsignedRemainder(Kind.Int, a, b);
-    }
-
-    /**
-     * Unsigned division for two numbers.
-     */
-    public static long divide(long a, long b) {
-        return unsignedDivide(Kind.Long, a, b);
-    }
-
-    /**
-     * Unsigned remainder for two numbers.
-     */
-    public static long remainder(long a, long b) {
-        return unsignedRemainder(Kind.Long, a, b);
-    }
-
-    @NodeIntrinsic(UnsignedDivNode.class)
-    private static native int unsignedDivide(@ConstantNodeParameter Kind kind, int a, int b);
-
-    @NodeIntrinsic(UnsignedDivNode.class)
-    private static native long unsignedDivide(@ConstantNodeParameter Kind kind, long a, long b);
-
-    @NodeIntrinsic(UnsignedRemNode.class)
-    private static native int unsignedRemainder(@ConstantNodeParameter Kind kind, int a, int b);
-
-    @NodeIntrinsic(UnsignedRemNode.class)
-    private static native long unsignedRemainder(@ConstantNodeParameter Kind kind, long a, long b);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/UnsignedMathSubstitutions.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,140 @@
+/*
+ * 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.snippets;
+
+import static com.oracle.graal.nodes.MaterializeNode.*;
+import static com.oracle.graal.nodes.calc.Condition.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.snippets.ClassSubstitution.*;
+
+/**
+ * Substitutions for {@link UnsignedMath}.
+ */
+@ClassSubstitution(UnsignedMath.class)
+public class UnsignedMathSubstitutions {
+
+    @MethodSubstitution
+    public static boolean aboveThan(int a, int b) {
+        return materialize(BT, b, a);
+    }
+
+    @MethodSubstitution
+    public static boolean aboveOrEqual(int a, int b) {
+        return !materialize(BT, a, b);
+    }
+
+    /**
+     * Unsigned comparison belowThan for two numbers.
+     */
+    @MethodSubstitution
+    public static boolean belowThan(int a, int b) {
+        return materialize(BT, a, b);
+    }
+
+    /**
+     * Unsigned comparison belowOrEqual for two numbers.
+     */
+    @MethodSubstitution
+    public static boolean belowOrEqual(int a, int b) {
+        return !materialize(BT, b, a);
+    }
+
+    /**
+     * Unsigned comparison aboveThan for two numbers.
+     */
+    @MethodSubstitution
+    public static boolean aboveThan(long a, long b) {
+        return materialize(BT, b, a);
+    }
+
+    /**
+     * Unsigned comparison aboveOrEqual for two numbers.
+     */
+    @MethodSubstitution
+    public static boolean aboveOrEqual(long a, long b) {
+        return !materialize(BT, a, b);
+    }
+
+    /**
+     * Unsigned comparison belowThan for two numbers.
+     */
+    @MethodSubstitution
+    public static boolean belowThan(long a, long b) {
+        return materialize(BT, a, b);
+    }
+
+    /**
+     * Unsigned comparison belowOrEqual for two numbers.
+     */
+    @MethodSubstitution
+    public static boolean belowOrEqual(long a, long b) {
+        return !materialize(BT, b, a);
+    }
+
+    /**
+     * Unsigned division for two numbers.
+     */
+    @MethodSubstitution
+    public static int divide(int a, int b) {
+        return unsignedDivide(Kind.Int, a, b);
+    }
+
+    /**
+     * Unsigned remainder for two numbers.
+     */
+    @MethodSubstitution
+    public static int remainder(int a, int b) {
+        return unsignedRemainder(Kind.Int, a, b);
+    }
+
+    /**
+     * Unsigned division for two numbers.
+     */
+    @MethodSubstitution
+    public static long divide(long a, long b) {
+        return unsignedDivide(Kind.Long, a, b);
+    }
+
+    /**
+     * Unsigned remainder for two numbers.
+     */
+    @MethodSubstitution
+    public static long remainder(long a, long b) {
+        return unsignedRemainder(Kind.Long, a, b);
+    }
+
+    @NodeIntrinsic(UnsignedDivNode.class)
+    private static native int unsignedDivide(@ConstantNodeParameter Kind kind, int a, int b);
+
+    @NodeIntrinsic(UnsignedDivNode.class)
+    private static native long unsignedDivide(@ConstantNodeParameter Kind kind, long a, long b);
+
+    @NodeIntrinsic(UnsignedRemNode.class)
+    private static native int unsignedRemainder(@ConstantNodeParameter Kind kind, int a, int b);
+
+    @NodeIntrinsic(UnsignedRemNode.class)
+    private static native long unsignedRemainder(@ConstantNodeParameter Kind kind, long a, long b);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/BranchProbabilityNode.java	Wed Jan 16 09:08:24 2013 +0100
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2012, 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.snippets.nodes;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+
+/**
+ * Instances of this node class will look for a preceding if node and put the given probability into the if node's taken
+ * probability. Then the branch probability node will be removed. This node is intended primarily for snippets, so that
+ * they can define their fast and slow paths.
+ */
+public class BranchProbabilityNode extends FixedWithNextNode implements Simplifiable {
+
+    private final double probability;
+
+    public BranchProbabilityNode(double probability) {
+        super(StampFactory.forVoid());
+        assert probability >= 0 && probability <= 1;
+        this.probability = probability;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        FixedNode current = this;
+        while (!(current instanceof BeginNode)) {
+            current = (FixedNode) current.predecessor();
+        }
+        BeginNode begin = (BeginNode) current;
+        assert begin.predecessor() instanceof IfNode : "explicit branch probability cannot follow a merge, only if nodes";
+        IfNode ifNode = (IfNode) begin.predecessor();
+        if (ifNode.trueSuccessor() == begin) {
+            ifNode.setTakenProbability(probability);
+        } else {
+            ifNode.setTakenProbability(1 - probability);
+        }
+
+        FixedNode next = next();
+        setNext(null);
+        ((FixedWithNextNode) predecessor()).setNext(next);
+        GraphUtil.killCFG(this);
+    }
+
+    @NodeIntrinsic
+    public static native void probability(@ConstantNodeParameter double probability);
+
+}
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Wed Jan 16 09:08:24 2013 +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.graal.word/src/com/oracle/graal/word/Word.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Wed Jan 16 09:08:24 2013 +0100
@@ -202,11 +202,11 @@
         return signedDivide((Word) val);
     }
     @Override
-    @Operation(node = IntegerMulNode.class)
+    @Operation(node = IntegerDivNode.class)
     public Word signedDivide(int val) {
         return signedDivide(intParam(val));
     }
-    @Operation(node = IntegerMulNode.class)
+    @Operation(node = IntegerDivNode.class)
     public Word signedDivide(Word val) {
         return box(unbox() / val.unbox());
     }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Wed Jan 16 09:08:24 2013 +0100
@@ -121,7 +121,7 @@
                         assert arguments.size() == 2;
                         ValueNode left = arguments.get(0);
                         ValueNode right = operation.rightOperandIsInt() ? toUnsigned(graph, arguments.get(1), Kind.Int) : fromSigned(graph, arguments.get(1));
-                        replace(invoke, nodeClassOp(graph, operation.node(), left, right));
+                        replace(invoke, nodeClassOp(graph, operation.node(), left, right, invoke));
                         break;
 
                     case COMPARISON:
@@ -215,10 +215,14 @@
         }
     }
 
-    private ValueNode nodeClassOp(StructuredGraph graph, Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right) {
+    private ValueNode nodeClassOp(StructuredGraph graph, Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right, Invoke invoke) {
         try {
             Constructor< ? extends ValueNode> constructor = nodeClass.getConstructor(Kind.class, ValueNode.class, ValueNode.class);
-            return graph.add(constructor.newInstance(wordKind, left, right));
+            ValueNode result = graph.add(constructor.newInstance(wordKind, left, right));
+            if (result instanceof FixedWithNextNode) {
+                graph.addBeforeFixed(invoke.node(), (FixedWithNextNode) result);
+            }
+            return result;
         } catch (Throwable ex) {
             throw new GraalInternalError(ex).addContext(nodeClass.getName());
         }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java	Wed Jan 16 09:08:24 2013 +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	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Wed Jan 16 09:08:24 2013 +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/graal/com.oracle.truffle.codegen.processor/src/META-INF/services/javax.annotation.processing.Processor	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/META-INF/services/javax.annotation.processing.Processor	Wed Jan 16 09:08:24 2013 +0100
@@ -1,1 +1,1 @@
-com.oracle.truffle.codegen.processor.TruffleProcessor
\ No newline at end of file
+com.oracle.truffle.codegen.processor.TruffleProcessor
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame	Wed Jan 16 09:08:24 2013 +0100
@@ -46,7 +46,7 @@
     public final Scanner scanner;
     public final Errors errors;
     private final NodeFactory factory;
-	-->declarations
+    -->declarations
     public Parser(Scanner scanner, NodeFactory factory) {
         this.scanner = scanner;
         this.factory = factory;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.frame	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.frame	Wed Jan 16 09:08:24 2013 +0100
@@ -403,7 +403,7 @@
             NextCh();
         }
     }
-	
+
 -->comments
 
     void CheckLiteral() {
@@ -418,7 +418,7 @@
     Token NextToken() {
         while (ch == ' ' || 
 -->scan1
-		) NextCh();
+        ) NextCh();
 -->scan2
         int recKind = noSym;
         int recEnd = pos;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg	Wed Jan 16 09:05:48 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg	Wed Jan 16 09:08:24 2013 +0100
@@ -28,7 +28,7 @@
 =
 Function 
 {
-	 Function
+    Function
 }
 .
 
@@ -86,7 +86,7 @@
 }
 ";"                                             (. result = factory.createPrint(expressions); .)
 .
-							
+
 ReturnStatement<out StatementNode result>
 =
 "return"
@@ -97,8 +97,8 @@
 =
 ValueExpression<out result>
 [
-    ("<" | ">" | "<=" | ">=" | "==" | "!=" )    (.	String op = t.val; .)
-    ValueExpression<out TypedNode right>        (.	result = factory.createBinary(op, result, right); .)
+    ("<" | ">" | "<=" | ">=" | "==" | "!=" )    (.  String op = t.val; .)
+    ValueExpression<out TypedNode right>        (.  result = factory.createBinary(op, result, right); .)
 ]
 .
 
--- a/mx/commands.py	Wed Jan 16 09:05:48 2013 +0100
+++ b/mx/commands.py	Wed Jan 16 09:08:24 2013 +0100
@@ -944,11 +944,11 @@
         benchmarks += sanitycheck.getBootstraps()
     #SPECjvm2008
     if ('specjvm2008' in args or 'all' in args):
-        benchmarks += [sanitycheck.getSPECjvm2008([], True, 120, 120)]
+        benchmarks += [sanitycheck.getSPECjvm2008([], False, True, 120, 120)]
     else:
         specjvms = [a[12:] for a in args if a.startswith('specjvm2008:')]
         for specjvm in specjvms:
-            benchmarks += [sanitycheck.getSPECjvm2008([specjvm], True, 120, 120)]
+            benchmarks += [sanitycheck.getSPECjvm2008([specjvm], False, True, 120, 120)]
             
     if ('specjbb2005' in args or 'all' in args):
         benchmarks += [sanitycheck.getSPECjbb2005()]
@@ -966,16 +966,20 @@
 def specjvm2008(args):
     """run one or all SPECjvm2008 benchmarks
 
-    All options begining with - will be passed to the vm except for -ikv -wt and -it.
+    All options begining with - will be passed to the vm except for -ikv -ict -wt and -it.
     Other options are supposed to be benchmark names and will be passed to SPECjvm2008."""
     benchArgs = [a for a in args if a[0] != '-']
     vmArgs = [a for a in args if a[0] == '-']
     wt = None
     it = None
     skipValid = False
+    skipCheck = False
     if '-v' in vmArgs:
         vmArgs.remove('-v')
         benchArgs.append('-v')
+    if '-ict' in vmArgs:
+        skipCheck = True
+        vmArgs.remove('-ict')
     if '-ikv' in vmArgs:
         skipValid = True
         vmArgs.remove('-ikv')
@@ -996,7 +1000,7 @@
         vmArgs.remove('-it')
         benchArgs.remove(args[itIdx+1])
     vm = _vm;
-    sanitycheck.getSPECjvm2008(benchArgs, skipValid, wt, it).bench(vm, opts=vmArgs)
+    sanitycheck.getSPECjvm2008(benchArgs, skipCheck, skipValid, wt, it).bench(vm, opts=vmArgs)
 
 def hsdis(args, copyToDir=None):
     """download the hsdis library
--- a/mx/projects	Wed Jan 16 09:05:48 2013 +0100
+++ b/mx/projects	Wed Jan 16 09:08:24 2013 +0100
@@ -237,7 +237,7 @@
 # graal.compiler.test
 project@com.oracle.graal.compiler.test@subDir=graal
 project@com.oracle.graal.compiler.test@sourceDirs=src
-project@com.oracle.graal.compiler.test@dependencies=JUNIT,com.oracle.graal.compiler,com.oracle.graal.java,com.oracle.graal.api.runtime
+project@com.oracle.graal.compiler.test@dependencies=com.oracle.graal.api.runtime,com.oracle.graal.printer,JUNIT
 project@com.oracle.graal.compiler.test@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.compiler.test@javaCompliance=1.7
 
--- a/mx/sanitycheck.py	Wed Jan 16 09:05:48 2013 +0100
+++ b/mx/sanitycheck.py	Wed Jan 16 09:08:24 2013 +0100
@@ -108,9 +108,9 @@
     success = re.compile(r"^Valid run, Score is  [0-9]+$")
     matcher = Matcher(score, {'const:group' : "const:SPECjbb2005", 'const:name' : 'const:score', 'const:score' : 'score'})
     classpath = ['jbb.jar', 'check.jar']
-    return Test("SPECjbb2005", ['spec.jbb.JBBmain', '-propfile', 'SPECjbb.props'] + benchArgs, [success], [error], [matcher], vmOpts=['-Xms3g', '-XX:+UseSerialGC', '-cp', os.pathsep.join(classpath)], defaultCwd=specjbb2005)
+    return Test("SPECjbb2005", ['spec.jbb.JBBmain', '-propfile', 'SPECjbb.props'] + benchArgs, [success], [error], [matcher], vmOpts=['-Xms3g', '-XX:+UseSerialGC', '-XX:-UseCompressedOops', '-cp', os.pathsep.join(classpath)], defaultCwd=specjbb2005)
     
-def getSPECjvm2008(benchArgs = [], skipKitValidation=False, warmupTime=None, iterationTime=None):
+def getSPECjvm2008(benchArgs = [], skipCheck=False, skipKitValidation=False, warmupTime=None, iterationTime=None):
     
     specjvm2008 = mx.get_env('SPECJVM2008')
     if specjvm2008 is None or not exists(join(specjvm2008, 'SPECjvm2008.jar')):
@@ -129,8 +129,10 @@
         opts += ['-it', str(iterationTime)]
     if skipKitValidation:
         opts += ['-ikv']
+    if skipCheck:
+        opts += ['-ict']
     
-    return Test("SPECjvm2008", ['-jar', 'SPECjvm2008.jar'] + opts + benchArgs, [success], [error], [matcher], vmOpts=['-Xms3g', '-XX:+UseSerialGC'], defaultCwd=specjvm2008)
+    return Test("SPECjvm2008", ['-jar', 'SPECjvm2008.jar'] + opts + benchArgs, [success], [error], [matcher], vmOpts=['-Xms3g', '-XX:+UseSerialGC', '-XX:-UseCompressedOops'], defaultCwd=specjvm2008)
 
 def getDacapos(level=SanityCheckLevel.Normal, gateBuildLevel=None, dacapoArgs=[]):
     checks = []
@@ -162,7 +164,7 @@
     dacapoMatcher = Matcher(dacapoTime, {'const:group' : "const:DaCapo", 'const:name' : 'benchmark', 'const:score' : 'time'}, startNewLine=True)
     dacapoMatcher1 = Matcher(dacapoTime1, {'const:group' : "const:DaCapo-1stRun", 'const:name' : 'benchmark', 'const:score' : 'time'})
     
-    return Test("DaCapo-" + name, ['-jar', dacapo, name, '-n', str(n), ] + dacapoArgs, [dacapoSuccess], [dacapoFail], [dacapoMatcher, dacapoMatcher1], ['-Xms2g', '-XX:+UseSerialGC'])
+    return Test("DaCapo-" + name, ['-jar', dacapo, name, '-n', str(n), ] + dacapoArgs, [dacapoSuccess], [dacapoFail], [dacapoMatcher, dacapoMatcher1], ['-Xms2g', '-XX:+UseSerialGC', '-XX:-UseCompressedOops'])
 
 def getScalaDacapos(level=SanityCheckLevel.Normal, gateBuildLevel=None, dacapoArgs=[]):
     checks = []
@@ -192,7 +194,7 @@
     
     dacapoMatcher = Matcher(dacapoTime, {'const:group' : "const:Scala-DaCapo", 'const:name' : 'benchmark', 'const:score' : 'time'})
     
-    return Test("Scala-DaCapo-" + name, ['-jar', dacapo, name, '-n', str(n), ] + dacapoArgs, [dacapoSuccess], [dacapoFail], [dacapoMatcher], ['-Xms2g', '-XX:+UseSerialGC'])
+    return Test("Scala-DaCapo-" + name, ['-jar', dacapo, name, '-n', str(n), ] + dacapoArgs, [dacapoSuccess], [dacapoFail], [dacapoMatcher], ['-Xms2g', '-XX:+UseSerialGC', '-XX:-UseCompressedOops'])
 
 def getBootstraps():
     time = re.compile(r"Bootstrapping Graal\.+ in (?P<time>[0-9]+) ms")
--- a/src/cpu/x86/vm/jniTypes_x86.hpp	Wed Jan 16 09:05:48 2013 +0100
+++ b/src/cpu/x86/vm/jniTypes_x86.hpp	Wed Jan 16 09:08:24 2013 +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	Wed Jan 16 09:05:48 2013 +0100
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Wed Jan 16 09:08:24 2013 +0100
@@ -609,6 +609,8 @@
   set_boolean("verifyOops", VerifyOops);
   set_boolean("useFastLocking", GraalUseFastLocking);
   set_boolean("useBiasedLocking", UseBiasedLocking);
+  set_boolean("usePopCountInstruction", UsePopCountInstruction);
+  set_boolean("useAESIntrinsics", UseAESIntrinsics);
   set_boolean("useTLAB", UseTLAB);
   set_int("codeEntryAlignment", CodeEntryAlignment);
   set_int("vmPageSize", os::vm_page_size());
@@ -732,6 +734,10 @@
   set_long("logPrimitiveStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_log_primitive_id)));
   set_long("logObjectStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_log_object_id)));
   set_long("logPrintfStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_log_printf_id)));
+  set_long("aescryptEncryptBlockStub", VmIds::addStub(StubRoutines::aescrypt_encryptBlock()));
+  set_long("aescryptDecryptBlockStub", VmIds::addStub(StubRoutines::aescrypt_decryptBlock()));
+  set_long("cipherBlockChainingEncryptAESCryptStub", VmIds::addStub(StubRoutines::cipherBlockChaining_encryptAESCrypt()));
+  set_long("cipherBlockChainingDecryptAESCryptStub", VmIds::addStub(StubRoutines::cipherBlockChaining_decryptAESCrypt()));
 
   set_int("deoptReasonNone", Deoptimization::Reason_none);
   set_int("deoptReasonNullCheck", Deoptimization::Reason_null_check);
@@ -938,6 +944,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 +1007,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 +1056,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() {
--- a/src/share/vm/oops/method.cpp	Wed Jan 16 09:05:48 2013 +0100
+++ b/src/share/vm/oops/method.cpp	Wed Jan 16 09:08:24 2013 +0100
@@ -724,6 +724,7 @@
     tty->cr();
   }
   if ((TraceDeoptimization || LogCompilation) && (xtty != NULL)) {
+    ResourceMark rm;
     ttyLocker ttyl;
     xtty->begin_elem("make_not_%scompilable thread='" UINTX_FORMAT "'",
                      is_osr ? "osr_" : "", os::current_thread_id());