changeset 9409:16a10b48e526

Merge
author Christos Kotselidis <christos.kotselidis@oracle.com>
date Sun, 28 Apr 2013 22:52:12 +0200
parents c21b1e5b515c (current diff) 5a74cbafe5b9 (diff)
children 3270cbd45e03
files graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/AllocatableValue.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArraySlowStubCall.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceSlowStubCall.java graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Reflection_getCallerClass01.java
diffstat 196 files changed, 3709 insertions(+), 1835 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/AllocatableValue.java	Sun Apr 28 22:34:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * 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.api.code;
-
-import com.oracle.graal.api.meta.*;
-
-/**
- * Common base class for values that can be manipulated by the register allocator.
- */
-public abstract class AllocatableValue extends Value {
-
-    private static final long serialVersionUID = 153019506717492133L;
-
-    /**
-     * Marker to tell the register allocator that no storage location needs to be allocated for this
-     * value.
-     */
-    @SuppressWarnings("serial") public static final AllocatableValue UNUSED = new AllocatableValue(Kind.Illegal) {
-
-        @Override
-        public String toString() {
-            return "-";
-        }
-    };
-
-    public AllocatableValue(Kind kind) {
-        super(kind);
-    }
-
-}
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java	Sun Apr 28 22:52:12 2013 +0200
@@ -76,17 +76,17 @@
      */
     private final int stackSize;
 
-    private final Value returnLocation;
+    private final AllocatableValue returnLocation;
 
     /**
      * The ordered locations in which the arguments are placed.
      */
-    private final Value[] argumentLocations;
+    private final AllocatableValue[] argumentLocations;
 
     /**
      * The locations used (and killed) by the call in addition to the arguments.
      */
-    private final Value[] temporaryLocations;
+    private final AllocatableValue[] temporaryLocations;
 
     /**
      * Creates a description of the registers and stack locations used by a call.
@@ -97,8 +97,8 @@
      *            call
      * @param argumentLocations the ordered locations in which the arguments are placed
      */
-    public CallingConvention(int stackSize, Value returnLocation, Value... argumentLocations) {
-        this(Value.NONE, stackSize, returnLocation, argumentLocations);
+    public CallingConvention(int stackSize, AllocatableValue returnLocation, AllocatableValue... argumentLocations) {
+        this(AllocatableValue.NONE, stackSize, returnLocation, argumentLocations);
     }
 
     /**
@@ -112,7 +112,7 @@
      *            call
      * @param argumentLocations the ordered locations in which the arguments are placed
      */
-    public CallingConvention(Value[] temporaryLocations, int stackSize, Value returnLocation, Value... argumentLocations) {
+    public CallingConvention(AllocatableValue[] temporaryLocations, int stackSize, AllocatableValue returnLocation, AllocatableValue... argumentLocations) {
         assert argumentLocations != null;
         assert temporaryLocations != null;
         assert returnLocation != null;
@@ -126,14 +126,14 @@
     /**
      * Gets the location for the return value or {@link Value#ILLEGAL} if a void call.
      */
-    public Value getReturn() {
+    public AllocatableValue getReturn() {
         return returnLocation;
     }
 
     /**
      * Gets the location for the {@code index}'th argument.
      */
-    public Value getArgument(int index) {
+    public AllocatableValue getArgument(int index) {
         return argumentLocations[index];
     }
 
@@ -155,7 +155,7 @@
      * Gets the locations used (and killed) by the call apart from the
      * {@linkplain #getArgument(int) arguments}.
      */
-    public Value[] getTemporaries() {
+    public AllocatableValue[] getTemporaries() {
         if (temporaryLocations.length == 0) {
             return temporaryLocations;
         }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java	Sun Apr 28 22:52:12 2013 +0200
@@ -303,6 +303,14 @@
             }
             sb.append(' ').append(bm).append(nl);
         }
+        RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo();
+        if (calleeSaveInfo != null) {
+            sb.append("callee-save-info:").append(nl);
+            Map<Integer, Register> map = calleeSaveInfo.slotsToRegisters(true);
+            for (Map.Entry<Integer, Register> e : map.entrySet()) {
+                sb.append("    ").append(e.getValue()).append(" -> ").append(formatter.formatStackSlot(e.getKey())).append(nl);
+            }
+        }
         BytecodeFrame frame = info.frame();
         if (frame != null) {
             append(sb, frame);
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.api.code;
 
+import static java.util.Collections.*;
+
 import java.io.*;
 import java.util.*;
 
@@ -366,7 +368,7 @@
      */
     public void recordDataReference(int codePos, Constant data, int alignment, boolean inlined) {
         assert codePos >= 0 && data != null;
-        getDataReferences().add(new DataPatch(codePos, data, alignment, inlined));
+        dataReferences.add(new DataPatch(codePos, data, alignment, inlined));
     }
 
     /**
@@ -390,7 +392,7 @@
      * @param handlerPos the position of the handler
      */
     public void recordExceptionHandler(int codePos, int handlerPos) {
-        getExceptionHandlers().add(new ExceptionHandler(codePos, handlerPos));
+        exceptionHandlers.add(new ExceptionHandler(codePos, handlerPos));
     }
 
     /**
@@ -405,11 +407,11 @@
 
     private void addInfopoint(Infopoint infopoint) {
         // The infopoints list must always be sorted
-        if (!getInfopoints().isEmpty() && getInfopoints().get(getInfopoints().size() - 1).pcOffset >= infopoint.pcOffset) {
+        if (!infopoints.isEmpty() && infopoints.get(infopoints.size() - 1).pcOffset >= infopoint.pcOffset) {
             // This re-sorting should be very rare
-            Collections.sort(getInfopoints());
+            Collections.sort(infopoints);
         }
-        getInfopoints().add(infopoint);
+        infopoints.add(infopoint);
     }
 
     /**
@@ -421,7 +423,7 @@
      */
     public Mark recordMark(int codePos, Object id, Mark[] references) {
         Mark mark = new Mark(codePos, id, references);
-        getMarks().add(mark);
+        marks.add(mark);
         return mark;
     }
 
@@ -505,6 +507,16 @@
         if (info != null) {
             appendRefMap(sb, "stackMap", info.getFrameRefMap());
             appendRefMap(sb, "registerMap", info.getRegisterRefMap());
+            RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo();
+            if (calleeSaveInfo != null) {
+                sb.append(" callee-save-info[");
+                String sep = "";
+                for (Map.Entry<Register, Integer> e : calleeSaveInfo.registersToSlots(true).entrySet()) {
+                    sb.append(sep).append(e.getKey()).append("->").append(e.getValue());
+                    sep = ", ";
+                }
+                sb.append(']');
+            }
             BytecodePosition codePos = info.getBytecodePosition();
             if (codePos != null) {
                 MetaUtil.appendLocation(sb.append(" "), codePos.getMethod(), codePos.getBCI());
@@ -528,27 +540,39 @@
      * @return the list of infopoints, sorted by {@link Site#pcOffset}
      */
     public List<Infopoint> getInfopoints() {
-        return infopoints;
+        if (infopoints.isEmpty()) {
+            return emptyList();
+        }
+        return unmodifiableList(infopoints);
     }
 
     /**
      * @return the list of data references
      */
     public List<DataPatch> getDataReferences() {
-        return dataReferences;
+        if (dataReferences.isEmpty()) {
+            return emptyList();
+        }
+        return unmodifiableList(dataReferences);
     }
 
     /**
      * @return the list of exception handlers
      */
     public List<ExceptionHandler> getExceptionHandlers() {
-        return exceptionHandlers;
+        if (exceptionHandlers.isEmpty()) {
+            return emptyList();
+        }
+        return unmodifiableList(exceptionHandlers);
     }
 
     /**
      * @return the list of marks
      */
     public List<Mark> getMarks() {
-        return marks;
+        if (marks.isEmpty()) {
+            return emptyList();
+        }
+        return unmodifiableList(marks);
     }
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java	Sun Apr 28 22:52:12 2013 +0200
@@ -26,8 +26,16 @@
 import java.util.*;
 
 /**
- * Represents the debugging information for a particular place in the code, which includes the code
- * position, a reference map, and deoptimization information.
+ * Represents the debugging information for a particular point of execution. This information
+ * includes:
+ * <ul>
+ * <li>a {@linkplain #getBytecodePosition() bytecode position}</li>
+ * <li>a reference map for {@linkplain #getRegisterRefMap() registers}</li>
+ * <li>a reference map for {@linkplain #getRegisterRefMap() stack slots} in the current frame</li>
+ * <li>a map from bytecode locals and operand stack slots to their values or locations from which
+ * their values can be read</li>
+ * <li>a map from the registers (in the caller's frame) to the slots where they are saved in the
+ * current frame</li>
  */
 public class DebugInfo implements Serializable {
 
@@ -37,6 +45,7 @@
     private final BitSet registerRefMap;
     private final BitSet frameRefMap;
     private final short deoptimizationReason;
+    private RegisterSaveLayout calleeSaveInfo;
 
     /**
      * Creates a new {@link DebugInfo} from the given values.
@@ -125,4 +134,20 @@
     public short getDeoptimizationReason() {
         return deoptimizationReason;
     }
+
+    /**
+     * Sets the map from the registers (in the caller's frame) to the slots where they are saved in
+     * the current frame.
+     */
+    public void setCalleeSaveInfo(RegisterSaveLayout calleeSaveInfo) {
+        this.calleeSaveInfo = calleeSaveInfo;
+    }
+
+    /**
+     * Gets the map from the registers (in the caller's frame) to the slots where they are saved in
+     * the current frame. If no such information is available, {@code null} is returned.
+     */
+    public RegisterSaveLayout getCalleeSaveInfo() {
+        return calleeSaveInfo;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterSaveLayout.java	Sun Apr 28 22:52:12 2013 +0200
@@ -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.api.code;
+
+import java.util.*;
+
+/**
+ * A map from registers to frame slots. This can be used to describe where callee saved registers
+ * are saved in a callee's frame.
+ */
+public class RegisterSaveLayout {
+
+    /**
+     * Keys.
+     */
+    private Register[] registers;
+
+    /**
+     * Slot indexes relative to stack pointer.
+     */
+    private int[] slots;
+
+    /**
+     * Creates a map from registers to frame slots.
+     * 
+     * @param registers the keys in the map
+     * @param slots frame slot index for each register in {@code registers}
+     */
+    public RegisterSaveLayout(Register[] registers, int[] slots) {
+        assert registers.length == slots.length;
+        this.registers = registers;
+        this.slots = slots;
+        assert registersToSlots(false).size() == registers.length : "non-unique registers";
+        assert new HashSet<>(registersToSlots(false).values()).size() == slots.length : "non-unqiue slots";
+    }
+
+    /**
+     * Gets this layout information as a {@link Map} from registers to slots.
+     */
+    public Map<Register, Integer> registersToSlots(boolean sorted) {
+        Map<Register, Integer> result;
+        if (sorted) {
+            result = new TreeMap<>();
+        } else {
+            result = new HashMap<>();
+        }
+        for (int i = 0; i < registers.length; i++) {
+            result.put(registers[i], slots[i]);
+        }
+        return result;
+    }
+
+    /**
+     * Gets this layout information as a {@link Map} from slots to registers.
+     */
+    public Map<Integer, Register> slotsToRegisters(boolean sorted) {
+        Map<Integer, Register> result;
+        if (sorted) {
+            result = new TreeMap<>();
+        } else {
+            result = new HashMap<>();
+        }
+        for (int i = 0; i < registers.length; i++) {
+            result.put(slots[i], registers[i]);
+        }
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return registersToSlots(true).toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AllocatableValue.java	Sun Apr 28 22:52:12 2013 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta;
+
+/**
+ * Common base class for values that are stored in some location that's managed by the register
+ * allocator (e.g. register, stack slot).
+ */
+public abstract class AllocatableValue extends Value {
+
+    private static final long serialVersionUID = 153019506717492133L;
+
+    public static final AllocatableValue[] NONE = {};
+
+    public AllocatableValue(Kind kind) {
+        super(kind);
+    }
+
+}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java	Sun Apr 28 22:52:12 2013 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.api.meta;
 
 import java.io.*;
+import java.util.*;
 
 import com.oracle.graal.api.meta.ProfilingInfo.*;
 
@@ -43,6 +44,8 @@
 
         private static final long serialVersionUID = 7838575753661305744L;
 
+        public static final ProfiledType[] EMPTY_ARRAY = new ProfiledType[0];
+
         private final ResolvedJavaType type;
         private final double probability;
 
@@ -78,6 +81,40 @@
             }
             return 0;
         }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            long temp;
+            temp = Double.doubleToLongBits(probability);
+            result = prime * result + (int) (temp ^ (temp >>> 32));
+            result = prime * result + type.hashCode();
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            ProfiledType other = (ProfiledType) obj;
+            if (Double.doubleToLongBits(probability) != Double.doubleToLongBits(other.probability)) {
+                return false;
+            }
+            return type.equals(other.type);
+        }
+
+        @Override
+        public String toString() {
+            return "{" + type.getName() + ", " + probability + "}";
+        }
     }
 
     private final TriState nullSeen;
@@ -100,6 +137,7 @@
     public JavaTypeProfile(TriState nullSeen, double notRecordedProbability, ProfiledType... ptypes) {
         this.nullSeen = nullSeen;
         this.ptypes = ptypes;
+        assert notRecordedProbability != Double.NaN;
         this.notRecordedProbability = notRecordedProbability;
         assert isSorted(ptypes);
     }
@@ -129,4 +167,154 @@
     public ProfiledType[] getTypes() {
         return ptypes;
     }
+
+    /**
+     * Searches for an entry of a given resolved Java type.
+     * 
+     * @param type the type for which an entry should be searched
+     * @return the entry or null if no entry for this type can be found
+     */
+    public ProfiledType findEntry(ResolvedJavaType type) {
+        if (ptypes != null) {
+            for (ProfiledType pt : ptypes) {
+                if (pt.getType() == type) {
+                    return pt;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("JavaTypeProfile[");
+        builder.append(this.nullSeen);
+        builder.append(", ");
+        if (ptypes != null) {
+            for (ProfiledType pt : ptypes) {
+                builder.append(pt.toString());
+                builder.append(", ");
+            }
+        }
+        builder.append(this.notRecordedProbability);
+        builder.append("]");
+        return builder.toString();
+    }
+
+    public JavaTypeProfile restrict(JavaTypeProfile otherProfile) {
+        if (otherProfile.getNotRecordedProbability() > 0.0) {
+            // Not useful for restricting since there is an unknown set of types occuring.
+            return this;
+        }
+
+        if (this.getNotRecordedProbability() > 0.0) {
+            // We are unrestricted, so the other profile is always a better estimate.
+            return otherProfile;
+        }
+
+        ArrayList<ProfiledType> result = new ArrayList<>();
+        for (int i = 0; i < getTypes().length; i++) {
+            ProfiledType ptype = getTypes()[i];
+            ResolvedJavaType type = ptype.getType();
+            if (otherProfile.isIncluded(type)) {
+                result.add(ptype);
+            }
+        }
+
+        TriState newNullSeen = (otherProfile.getNullSeen() == TriState.FALSE) ? TriState.FALSE : this.nullSeen;
+        double newNotRecorded = this.notRecordedProbability;
+        return createAdjustedProfile(result, newNullSeen, newNotRecorded);
+    }
+
+    public boolean isIncluded(ResolvedJavaType type) {
+        if (this.getNotRecordedProbability() > 0.0) {
+            return true;
+        } else {
+            for (int i = 0; i < getTypes().length; i++) {
+                ProfiledType ptype = getTypes()[i];
+                ResolvedJavaType curType = ptype.getType();
+                if (curType == type) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public JavaTypeProfile restrict(ResolvedJavaType declaredType, boolean nonNull) {
+        ArrayList<ProfiledType> result = new ArrayList<>();
+        for (int i = 0; i < getTypes().length; i++) {
+            ProfiledType ptype = getTypes()[i];
+            ResolvedJavaType type = ptype.getType();
+            if (declaredType.isAssignableFrom(type)) {
+                result.add(ptype);
+            }
+        }
+
+        TriState newNullSeen = (nonNull) ? TriState.FALSE : this.nullSeen;
+        double newNotRecorded = this.getNotRecordedProbability();
+        // Assume for the types not recorded, the incompatibility rate is the same.
+        if (getTypes().length != 0) {
+            newNotRecorded *= ((double) result.size() / (double) getTypes().length);
+        }
+        return createAdjustedProfile(result, newNullSeen, newNotRecorded);
+    }
+
+    private JavaTypeProfile createAdjustedProfile(ArrayList<ProfiledType> result, TriState newNullSeen, double newNotRecorded) {
+        if (result.size() != this.getTypes().length || newNotRecorded != getNotRecordedProbability() || newNullSeen != this.nullSeen) {
+            if (result.size() == 0) {
+                return new JavaTypeProfile(newNullSeen, 1.0, ProfiledType.EMPTY_ARRAY);
+            }
+            double probabilitySum = 0.0;
+            for (int i = 0; i < result.size(); i++) {
+                probabilitySum += result.get(i).getProbability();
+            }
+            probabilitySum += newNotRecorded;
+
+            double factor = 1.0 / probabilitySum; // Normalize to 1.0
+            assert factor > 1.0;
+            ProfiledType[] newResult = new ProfiledType[result.size()];
+            for (int i = 0; i < newResult.length; ++i) {
+                ProfiledType curType = result.get(i);
+                newResult[i] = new ProfiledType(curType.getType(), Math.min(1.0, curType.getProbability() * factor));
+            }
+            double newNotRecordedTypeProbability = Math.min(1.0, newNotRecorded * factor);
+            return new JavaTypeProfile(newNullSeen, newNotRecordedTypeProbability, newResult);
+        }
+        return this;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other == this) {
+            return true;
+        }
+        if (other instanceof JavaTypeProfile) {
+            JavaTypeProfile javaTypeProfile = (JavaTypeProfile) other;
+            if (javaTypeProfile.nullSeen != nullSeen) {
+                return false;
+            }
+            if (javaTypeProfile.notRecordedProbability != notRecordedProbability) {
+                return false;
+            }
+            if (javaTypeProfile.ptypes.length != ptypes.length) {
+                return false;
+            }
+
+            for (int i = 0; i < ptypes.length; ++i) {
+                if (!ptypes[i].equals(javaTypeProfile.ptypes[i])) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return nullSeen.hashCode() + (int) Double.doubleToLongBits(notRecordedProbability) + ptypes.length * 13;
+    }
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Sun Apr 28 22:52:12 2013 +0200
@@ -24,7 +24,6 @@
 
 import java.lang.annotation.*;
 import java.lang.reflect.*;
-import java.lang.reflect.Method;
 import java.util.*;
 
 /**
@@ -202,4 +201,11 @@
      * @return The newly created and initialized object.
      */
     Constant newInstance(Constant[] arguments);
+
+    /**
+     * Gets the encoding of (that is, a constant representing the value of) this method.
+     * 
+     * @return a constant representing a reference to this method
+     */
+    Constant getEncoding();
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Sun Apr 28 22:52:12 2013 +0200
@@ -32,9 +32,7 @@
 
     private static final long serialVersionUID = -6909397188697766469L;
 
-    public static final Value[] NONE = {};
-
-    @SuppressWarnings("serial") public static final Value ILLEGAL = new Value(Kind.Illegal) {
+    @SuppressWarnings("serial") public static final AllocatableValue ILLEGAL = new AllocatableValue(Kind.Illegal) {
 
         @Override
         public String toString() {
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Sun Apr 28 22:52:12 2013 +0200
@@ -90,7 +90,7 @@
     public static class AMD64SpillMoveFactory implements LIR.SpillMoveFactory {
 
         @Override
-        public LIRInstruction createMove(Value result, Value input) {
+        public LIRInstruction createMove(AllocatableValue result, Value input) {
             return AMD64LIRGenerator.createMove(result, input);
         }
     }
@@ -143,8 +143,10 @@
         return result;
     }
 
-    private static AMD64LIRInstruction createMove(Value dst, Value src) {
-        if (isRegister(src) || isStackSlot(dst)) {
+    private static AMD64LIRInstruction createMove(AllocatableValue dst, Value src) {
+        if (src instanceof AMD64AddressValue) {
+            return new LeaOp(dst, (AMD64AddressValue) src);
+        } else if (isRegister(src) || isStackSlot(dst)) {
             return new MoveFromRegOp(dst, src);
         } else {
             return new MoveToRegOp(dst, src);
@@ -152,24 +154,23 @@
     }
 
     @Override
-    public void emitMove(Value dst, Value src) {
+    public void emitMove(AllocatableValue dst, Value src) {
         append(createMove(dst, src));
     }
 
-    private AMD64AddressValue prepareAddress(Kind kind, Value base, long displacement, Value index, int scale) {
+    @Override
+    public AMD64AddressValue emitAddress(Value base, long displacement, Value index, int scale) {
         AllocatableValue baseRegister;
         long finalDisp = displacement;
         if (isConstant(base)) {
             if (asConstant(base).isNull()) {
-                baseRegister = AllocatableValue.UNUSED;
+                baseRegister = Value.ILLEGAL;
             } else if (asConstant(base).getKind() != Kind.Object && !runtime.needsDataPatch(asConstant(base))) {
                 finalDisp += asConstant(base).asLong();
-                baseRegister = AllocatableValue.UNUSED;
+                baseRegister = Value.ILLEGAL;
             } else {
                 baseRegister = load(base);
             }
-        } else if (base == Value.ILLEGAL) {
-            baseRegister = AllocatableValue.UNUSED;
         } else {
             baseRegister = asAllocatable(base);
         }
@@ -180,12 +181,12 @@
             scaleEnum = Scale.fromInt(scale);
             if (isConstant(index)) {
                 finalDisp += asConstant(index).asLong() * scale;
-                indexRegister = AllocatableValue.UNUSED;
+                indexRegister = Value.ILLEGAL;
             } else {
                 indexRegister = asAllocatable(index);
             }
         } else {
-            indexRegister = AllocatableValue.UNUSED;
+            indexRegister = Value.ILLEGAL;
             scaleEnum = Scale.Times1;
         }
 
@@ -195,9 +196,9 @@
         } else {
             displacementInt = 0;
             AllocatableValue displacementRegister = load(Constant.forLong(finalDisp));
-            if (baseRegister == AllocatableValue.UNUSED) {
+            if (baseRegister == Value.ILLEGAL) {
                 baseRegister = displacementRegister;
-            } else if (indexRegister == AllocatableValue.UNUSED) {
+            } else if (indexRegister == Value.ILLEGAL) {
                 indexRegister = displacementRegister;
                 scaleEnum = Scale.Times1;
             } else {
@@ -205,44 +206,44 @@
             }
         }
 
-        return new AMD64AddressValue(kind, baseRegister, indexRegister, scaleEnum, displacementInt);
+        return new AMD64AddressValue(target().wordKind, baseRegister, indexRegister, scaleEnum, displacementInt);
+    }
+
+    private AMD64AddressValue asAddress(Value address) {
+        if (address instanceof AMD64AddressValue) {
+            return (AMD64AddressValue) address;
+        } else {
+            return emitAddress(address, 0, Value.ILLEGAL, 0);
+        }
     }
 
     @Override
-    public Variable emitLoad(Kind kind, Value base, long displacement, Value index, int scale, DeoptimizingNode deopting) {
-        AMD64AddressValue loadAddress = prepareAddress(kind, base, displacement, index, scale);
-        Variable result = newVariable(loadAddress.getKind());
-        append(new LoadOp(result, loadAddress, deopting != null ? state(deopting) : null));
+    public Variable emitLoad(Kind kind, Value address, DeoptimizingNode deopting) {
+        AMD64AddressValue loadAddress = asAddress(address);
+        Variable result = newVariable(kind);
+        append(new LoadOp(kind, result, loadAddress, deopting != null ? state(deopting) : null));
         return result;
     }
 
     @Override
-    public void emitStore(Kind kind, Value base, long displacement, Value index, int scale, Value inputVal, DeoptimizingNode deopting) {
-        AMD64AddressValue storeAddress = prepareAddress(kind, base, displacement, index, scale);
+    public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode deopting) {
+        AMD64AddressValue storeAddress = asAddress(address);
         LIRFrameState state = deopting != null ? state(deopting) : null;
 
         if (isConstant(inputVal)) {
             Constant c = asConstant(inputVal);
             if (canStoreConstant(c)) {
-                append(new StoreConstantOp(storeAddress, c, state));
+                append(new StoreConstantOp(kind, storeAddress, c, state));
                 return;
             }
         }
 
         Variable input = load(inputVal);
-        append(new StoreOp(storeAddress, input, state));
+        append(new StoreOp(kind, storeAddress, input, state));
     }
 
     @Override
-    public Variable emitLea(Value base, long displacement, Value index, int scale) {
-        Variable result = newVariable(target().wordKind);
-        AMD64AddressValue address = prepareAddress(result.getKind(), base, displacement, index, scale);
-        append(new LeaOp(result, address));
-        return result;
-    }
-
-    @Override
-    public Variable emitLea(StackSlot address) {
+    public Variable emitAddress(StackSlot address) {
         Variable result = newVariable(target().wordKind);
         append(new StackLeaOp(result, address));
         return result;
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,23 +22,19 @@
  */
 package com.oracle.graal.compiler.ptx.test;
 
-import com.oracle.graal.api.code.CodeCacheProvider;
-import com.oracle.graal.api.code.CompilationResult;
-import com.oracle.graal.api.code.SpeculationLog;
-import com.oracle.graal.api.code.TargetDescription;
-import com.oracle.graal.api.runtime.Graal;
-import com.oracle.graal.compiler.GraalCompiler;
-import com.oracle.graal.compiler.ptx.PTXBackend;
-import com.oracle.graal.compiler.test.GraalCompilerTest;
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.java.GraphBuilderConfiguration;
-import com.oracle.graal.java.GraphBuilderPhase;
-import com.oracle.graal.hotspot.HotSpotGraalRuntime;
-import com.oracle.graal.nodes.StructuredGraph;
-import com.oracle.graal.phases.OptimisticOptimizations;
-import com.oracle.graal.phases.PhasePlan;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.ptx.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.PhasePlan.PhasePosition;
-import com.oracle.graal.ptx.PTX;
+import com.oracle.graal.ptx.*;
 
 public abstract class PTXTestBase extends GraalCompilerTest {
 
@@ -48,14 +44,12 @@
         TargetDescription target = new TargetDescription(new PTX(), true, 1, 0, true);
         PTXBackend ptxBackend = new PTXBackend(Graal.getRequiredCapability(CodeCacheProvider.class), target);
         PhasePlan phasePlan = new PhasePlan();
-        GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(),
-                                                                    OptimisticOptimizations.NONE);
+        GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.NONE);
         phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
         phasePlan.addPhase(PhasePosition.AFTER_PARSING, new PTXPhase());
         new PTXPhase().apply(graph);
-        CompilationResult result = GraalCompiler.compileMethod(runtime, HotSpotGraalRuntime.getInstance().getReplacements(),
-                                                               ptxBackend, target, graph.method(), graph, null, phasePlan,
-                                                               OptimisticOptimizations.NONE, new SpeculationLog());
+        CompilationResult result = GraalCompiler.compileMethod(runtime, graalRuntime().getReplacements(), ptxBackend, target, graph.method(), graph, null, phasePlan, OptimisticOptimizations.NONE,
+                        new SpeculationLog());
         return result;
     }
 
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Sun Apr 28 22:52:12 2013 +0200
@@ -28,17 +28,13 @@
 import static com.oracle.graal.lir.ptx.PTXBitManipulationOp.IntrinsicOpcode.*;
 import static com.oracle.graal.lir.ptx.PTXCompare.*;
 
-import com.oracle.graal.api.code.AllocatableValue;
 import com.oracle.graal.api.code.CodeCacheProvider;
 import com.oracle.graal.api.code.DeoptimizationAction;
 import com.oracle.graal.api.code.RuntimeCallTarget;
 import com.oracle.graal.api.code.StackSlot;
 import com.oracle.graal.api.code.TargetDescription;
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.api.meta.Constant;
-import com.oracle.graal.api.meta.Kind;
-import com.oracle.graal.api.meta.ResolvedJavaMethod;
-import com.oracle.graal.api.meta.Value;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.NumUtil;
 import com.oracle.graal.compiler.gen.LIRGenerator;
 import com.oracle.graal.compiler.target.LIRGenLowerable;
@@ -84,7 +80,7 @@
     public static class PTXSpillMoveFactory implements LIR.SpillMoveFactory {
 
         @Override
-        public LIRInstruction createMove(Value result, Value input) {
+        public LIRInstruction createMove(AllocatableValue result, Value input) {
             throw new InternalError("NYI");
         }
     }
@@ -129,7 +125,7 @@
     }
 
     @Override
-    public void emitMove(Value dst, Value src) {
+    public void emitMove(AllocatableValue dst, Value src) {
         if (isRegister(src) || isStackSlot(dst)) {
             append(new MoveFromRegOp(dst, src));
         } else {
@@ -137,20 +133,19 @@
         }
     }
 
-    private PTXAddressValue prepareAddress(Kind kind, Value base, long displacement, Value index, int scale) {
+    @Override
+    public PTXAddressValue emitAddress(Value base, long displacement, Value index, int scale) {
         AllocatableValue baseRegister;
         long finalDisp = displacement;
         if (isConstant(base)) {
             if (asConstant(base).isNull()) {
-                baseRegister = AllocatableValue.UNUSED;
+                baseRegister = Value.ILLEGAL;
             } else if (asConstant(base).getKind() != Kind.Object) {
                 finalDisp += asConstant(base).asLong();
-                baseRegister = AllocatableValue.UNUSED;
+                baseRegister = Value.ILLEGAL;
             } else {
                 baseRegister = load(base);
             }
-        } else if (base == Value.ILLEGAL) {
-            baseRegister = AllocatableValue.UNUSED;
         } else {
             baseRegister = asAllocatable(base);
         }
@@ -166,7 +161,7 @@
                     indexRegister = index;
                 }
 
-                if (baseRegister == AllocatableValue.UNUSED) {
+                if (baseRegister == Value.ILLEGAL) {
                     baseRegister = asAllocatable(indexRegister);
                 } else {
                     Variable newBase = newVariable(Kind.Int);
@@ -177,31 +172,34 @@
             }
         }
 
-        return new PTXAddressValue(kind, baseRegister, finalDisp);
+        return new PTXAddressValue(target().wordKind, baseRegister, finalDisp);
+    }
+
+    private PTXAddressValue asAddress(Value address) {
+        if (address instanceof PTXAddressValue) {
+            return (PTXAddressValue) address;
+        } else {
+            return emitAddress(address, 0, Value.ILLEGAL, 0);
+        }
     }
 
     @Override
-    public Variable emitLoad(Kind kind, Value base, long displacement, Value index, int scale, DeoptimizingNode deopting) {
-        PTXAddressValue loadAddress = prepareAddress(kind, base, displacement, index, scale);
-        Variable result = newVariable(loadAddress.getKind());
-        append(new LoadOp(result, loadAddress, deopting != null ? state(deopting) : null));
+    public Variable emitLoad(Kind kind, Value address, DeoptimizingNode deopting) {
+        PTXAddressValue loadAddress = asAddress(address);
+        Variable result = newVariable(kind);
+        append(new LoadOp(kind, result, loadAddress, deopting != null ? state(deopting) : null));
         return result;
     }
 
     @Override
-    public void emitStore(Kind kind, Value base, long displacement, Value index, int scale, Value inputVal, DeoptimizingNode deopting) {
-        PTXAddressValue storeAddress = prepareAddress(kind, base, displacement, index, scale);
+    public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode deopting) {
+        PTXAddressValue storeAddress = asAddress(address);
         Variable input = load(inputVal);
-        append(new StoreOp(storeAddress, input, deopting != null ? state(deopting) : null));
+        append(new StoreOp(kind, storeAddress, input, deopting != null ? state(deopting) : null));
     }
 
     @Override
-    public Variable emitLea(Value base, long displacement, Value index, int scale) {
-        throw new InternalError("NYI");
-    }
-
-    @Override
-    public Variable emitLea(StackSlot address) {
+    public Variable emitAddress(StackSlot address) {
         throw new InternalError("NYI");
     }
 
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Sun Apr 28 22:52:12 2013 +0200
@@ -208,31 +208,31 @@
     }
 
     @Override
-    public void emitMove(Value dst, Value src) {
+    public void emitMove(AllocatableValue dst, Value src) {
         // SPARC: Auto-generated method stub
 
     }
 
     @Override
-    public Value emitLoad(Kind kind, Value base, long displacement, Value index, int scale, DeoptimizingNode canTrap) {
+    public Value emitAddress(Value base, long displacement, Value index, int scale) {
         // SPARC: Auto-generated method stub
         return null;
     }
 
     @Override
-    public void emitStore(Kind kind, Value base, long displacement, Value index, int scale, Value input, DeoptimizingNode canTrap) {
+    public Value emitLoad(Kind kind, Value address, DeoptimizingNode canTrap) {
+        // SPARC: Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public void emitStore(Kind kind, Value address, Value input, DeoptimizingNode canTrap) {
         // SPARC: Auto-generated method stub
 
     }
 
     @Override
-    public Value emitLea(Value base, long displacement, Value index, int scale) {
-        // SPARC: Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public Value emitLea(StackSlot address) {
+    public Value emitAddress(StackSlot address) {
         // SPARC: Auto-generated method stub
         return null;
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,15 +22,11 @@
  */
 package com.oracle.graal.compiler.test;
 
-import java.util.*;
-
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.Lowerable.*;
 import com.oracle.graal.phases.common.*;
@@ -96,36 +92,10 @@
 
                 Debug.dump(graph, "After lowering");
 
-                ArrayList<MergeNode> merges = new ArrayList<>();
-                ArrayList<FloatingReadNode> reads = new ArrayList<>();
-                for (Node n : graph.getNodes()) {
-                    if (n instanceof MergeNode) {
-                        // check shape
-                        MergeNode merge = (MergeNode) n;
-
-                        if (merge.inputs().count() == 2) {
-                            for (EndNode m : merge.forwardEnds()) {
-                                if (m.predecessor() != null && m.predecessor() instanceof BeginNode && m.predecessor().predecessor() instanceof IfNode) {
-                                    IfNode o = (IfNode) m.predecessor().predecessor();
-                                    if (o.falseSuccessor().next() instanceof DeoptimizeNode) {
-                                        merges.add(merge);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    if (n instanceof IntegerAddNode) {
-                        IntegerAddNode ian = (IntegerAddNode) n;
-
-                        Assert.assertTrue(ian.y() instanceof ConstantNode);
-                        Assert.assertTrue(ian.x() instanceof FloatingReadNode);
-                        reads.add((FloatingReadNode) ian.x());
-                    }
-                }
-
-                Assert.assertTrue(merges.size() >= reads.size());
-                for (int i = 0; i < reads.size(); i++) {
-                    assertOrderedAfterSchedule(graph, merges.get(i), reads.get(i));
+                for (FloatingReadNode node : graph.getNodes(LocalNode.class).first().usages().filter(FloatingReadNode.class)) {
+                    // Checking that the parameter a is not directly used for the access to field
+                    // x10 (because x10 must be guarded by the checkcast).
+                    Assert.assertTrue(node.location().locationIdentity() == LocationNode.FINAL_LOCATION);
                 }
             }
         });
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Sun Apr 28 22:52:12 2013 +0200
@@ -133,6 +133,8 @@
                     new IterativeConditionalEliminationPhase().apply(graph, highTierContext);
                 }
             }
+        } else {
+            TypeProfileProxyNode.cleanFromGraph(graph);
         }
 
         plan.runPhases(PhasePosition.HIGH_LEVEL, graph);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Sun Apr 28 22:52:12 2013 +0200
@@ -409,7 +409,7 @@
      * The {@linkplain RegisterValue register} or {@linkplain Variable variable} for this interval
      * prior to register allocation.
      */
-    public final Value operand;
+    public final AllocatableValue operand;
 
     /**
      * The operand number for this interval's {@linkplain #operand operand}.
@@ -420,7 +420,7 @@
      * The {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to this
      * interval.
      */
-    private Value location;
+    private AllocatableValue location;
 
     /**
      * The stack slot to which all splits of this interval are spilled if necessary.
@@ -498,7 +498,7 @@
      */
     private Interval locationHint;
 
-    void assignLocation(Value newLocation) {
+    void assignLocation(AllocatableValue newLocation) {
         if (isRegister(newLocation)) {
             assert this.location == null : "cannot re-assign location for " + this;
             if (newLocation.getKind() == Kind.Illegal && kind != Kind.Illegal) {
@@ -518,7 +518,7 @@
      * Gets the {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to
      * this interval.
      */
-    public Value location() {
+    public AllocatableValue location() {
         return location;
     }
 
@@ -673,7 +673,7 @@
      */
     static final Interval EndMarker = new Interval(Value.ILLEGAL, -1);
 
-    Interval(Value operand, int operandNumber) {
+    Interval(AllocatableValue operand, int operandNumber) {
         assert operand != null;
         this.operand = operand;
         this.operandNumber = operandNumber;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Sun Apr 28 22:52:12 2013 +0200
@@ -206,7 +206,7 @@
     /**
      * Gets the operand denoted by a given operand number.
      */
-    private Value operandFor(int operandNumber) {
+    private AllocatableValue operandFor(int operandNumber) {
         if (operandNumber < firstVariableNumber) {
             assert operandNumber >= 0;
             return registers[operandNumber].asValue();
@@ -281,7 +281,7 @@
      * @param operand the operand for the interval
      * @return the created interval
      */
-    Interval createInterval(Value operand) {
+    Interval createInterval(AllocatableValue operand) {
         assert isLegal(operand);
         int operandNumber = operandNumber(operand);
         Interval interval = new Interval(operand, operandNumber);
@@ -346,7 +346,7 @@
         return intervals[operandNumber];
     }
 
-    Interval getOrCreateInterval(Value operand) {
+    Interval getOrCreateInterval(AllocatableValue operand) {
         Interval ret = intervalFor(operand);
         if (ret == null) {
             return createInterval(operand);
@@ -555,8 +555,8 @@
                             insertionBuffer.init(instructions);
                         }
 
-                        Value fromLocation = interval.location();
-                        Value toLocation = canonicalSpillOpr(interval);
+                        AllocatableValue fromLocation = interval.location();
+                        AllocatableValue toLocation = canonicalSpillOpr(interval);
 
                         assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + interval.spillState();
                         assert isStackSlot(toLocation) : "to operand must be a stack slot";
@@ -968,7 +968,7 @@
         TTY.println(blockData.get(block).liveOut.toString());
     }
 
-    void addUse(Value operand, int from, int to, RegisterPriority registerPriority, Kind kind) {
+    void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, Kind kind) {
         if (!isProcessed(operand)) {
             return;
         }
@@ -987,7 +987,7 @@
         interval.addUsePos(to & ~1, registerPriority);
     }
 
-    void addTemp(Value operand, int tempPos, RegisterPriority registerPriority, Kind kind) {
+    void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, Kind kind) {
         if (!isProcessed(operand)) {
             return;
         }
@@ -1008,7 +1008,7 @@
         return !isRegister(operand) || attributes(asRegister(operand)).isAllocatable();
     }
 
-    void addDef(Value operand, int defPos, RegisterPriority registerPriority, Kind kind) {
+    void addDef(AllocatableValue operand, int defPos, RegisterPriority registerPriority, Kind kind) {
         if (!isProcessed(operand)) {
             return;
         }
@@ -1114,8 +1114,8 @@
                 @Override
                 protected Value doValue(Value registerHint) {
                     if (isVariableOrRegister(registerHint)) {
-                        Interval from = getOrCreateInterval(registerHint);
-                        Interval to = getOrCreateInterval(targetValue);
+                        Interval from = getOrCreateInterval((AllocatableValue) registerHint);
+                        Interval to = getOrCreateInterval((AllocatableValue) targetValue);
 
                         // hints always point from def to use
                         if (hintAtDef) {
@@ -1156,7 +1156,7 @@
             BitSet live = blockData.get(block).liveOut;
             for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) {
                 assert live.get(operandNum) : "should not stop here otherwise";
-                Value operand = operandFor(operandNum);
+                AllocatableValue operand = operandFor(operandNum);
                 if (GraalOptions.TraceLinearScanLevel >= 2) {
                     TTY.println("live in %s to %d", operand, blockTo + 2);
                 }
@@ -1197,7 +1197,7 @@
                     @Override
                     public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
                         if (isVariableOrRegister(operand)) {
-                            addDef(operand, opId, registerPriorityOfOutputOperand(op), operand.getKind().getStackKind());
+                            addDef((AllocatableValue) operand, opId, registerPriorityOfOutputOperand(op), operand.getKind().getStackKind());
                             addRegisterHint(op, operand, mode, flags, true);
                         }
                         return operand;
@@ -1208,7 +1208,7 @@
                     @Override
                     public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
                         if (isVariableOrRegister(operand)) {
-                            addTemp(operand, opId, RegisterPriority.MustHaveRegister, operand.getKind().getStackKind());
+                            addTemp((AllocatableValue) operand, opId, RegisterPriority.MustHaveRegister, operand.getKind().getStackKind());
                             addRegisterHint(op, operand, mode, flags, false);
                         }
                         return operand;
@@ -1220,7 +1220,7 @@
                     public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
                         if (isVariableOrRegister(operand)) {
                             RegisterPriority p = registerPriorityOfInputOperand(flags);
-                            addUse(operand, blockFrom, opId + 1, p, operand.getKind().getStackKind());
+                            addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getKind().getStackKind());
                             addRegisterHint(op, operand, mode, flags, false);
                         }
                         return operand;
@@ -1232,7 +1232,7 @@
                     public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
                         if (isVariableOrRegister(operand)) {
                             RegisterPriority p = registerPriorityOfInputOperand(flags);
-                            addUse(operand, blockFrom, opId, p, operand.getKind().getStackKind());
+                            addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getKind().getStackKind());
                             addRegisterHint(op, operand, mode, flags, false);
                         }
                         return operand;
@@ -1247,7 +1247,7 @@
 
                     @Override
                     public Value doValue(Value operand) {
-                        addUse(operand, blockFrom, opId + 1, RegisterPriority.None, operand.getKind().getStackKind());
+                        addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getKind().getStackKind());
                         return operand;
                     }
                 });
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java	Sun Apr 28 22:52:12 2013 +0200
@@ -196,8 +196,8 @@
         assert fromInterval.kind() == toInterval.kind() : "move between different types";
         assert insertIdx != -1 : "must setup insert position first";
 
-        Value fromOpr = fromInterval.operand;
-        Value toOpr = toInterval.operand;
+        AllocatableValue fromOpr = fromInterval.operand;
+        AllocatableValue toOpr = toInterval.operand;
 
         insertionBuffer.append(insertIdx, allocator.ir.spillMoveFactory.createMove(toOpr, fromOpr));
 
@@ -210,7 +210,7 @@
         assert fromOpr.getKind() == toInterval.kind() : "move between different types";
         assert insertIdx != -1 : "must setup insert position first";
 
-        Value toOpr = toInterval.operand;
+        AllocatableValue toOpr = toInterval.operand;
         insertionBuffer.append(insertIdx, allocator.ir.spillMoveFactory.createMove(toOpr, fromOpr));
 
         if (GraalOptions.TraceLinearScanLevel >= 4) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Sun Apr 28 22:52:12 2013 +0200
@@ -52,7 +52,7 @@
 /**
  * This class traverses the HIR instructions and generates LIR instructions from them.
  */
-public abstract class LIRGenerator extends LIRGeneratorTool {
+public abstract class LIRGenerator implements LIRGeneratorTool {
 
     public final FrameMap frameMap;
     public final NodeMap<Value> nodeOperands;
@@ -168,8 +168,8 @@
 
     @Override
     public Value setResult(ValueNode x, Value operand) {
-        assert (isVariable(operand) && x.kind() == operand.getKind()) || (isRegister(operand) && !attributes(asRegister(operand)).isAllocatable()) ||
-                        (isConstant(operand) && x.kind() == operand.getKind().getStackKind()) : operand.getKind() + " for node " + x;
+        assert (!isVariable(operand) || x.kind() == operand.getKind()) : operand.getKind() + " for node " + x;
+        assert (!isRegister(operand) || !attributes(asRegister(operand)).isAllocatable());
         assert operand(x) == null : "operand cannot be set twice";
         assert operand != null && isLegal(operand) : "operand must be legal";
         assert operand.getKind().getStackKind() == x.kind() : operand.getKind().getStackKind() + " must match " + x.kind();
@@ -251,7 +251,7 @@
      * @return the operand representing the ABI defined location used return a value of kind
      *         {@code kind}
      */
-    public Value resultOperandFor(Kind kind) {
+    public AllocatableValue resultOperandFor(Kind kind) {
         if (kind == Kind.Void) {
             return ILLEGAL;
         }
@@ -461,7 +461,7 @@
 
     @Override
     public void visitReturn(ReturnNode x) {
-        Value operand = Value.ILLEGAL;
+        AllocatableValue operand = ILLEGAL;
         if (x.result() != null) {
             operand = resultOperandFor(x.result().kind());
             emitMove(operand, operand(x.result()));
@@ -630,7 +630,7 @@
 
     protected abstract void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info);
 
-    protected static Value toStackKind(Value value) {
+    protected static AllocatableValue toStackKind(AllocatableValue value) {
         if (value.getKind().getStackKind() != value.getKind()) {
             // We only have stack-kinds in the LIR, so convert the operand kind for values from the
             // calling convention.
@@ -651,7 +651,7 @@
         int j = 0;
         for (ValueNode arg : arguments) {
             if (arg != null) {
-                Value operand = toStackKind(cc.getArgument(j));
+                AllocatableValue operand = toStackKind(cc.getArgument(j));
                 emitMove(operand, operand(arg));
                 result[j] = operand;
                 j++;
@@ -672,7 +672,7 @@
         Value[] argLocations = new Value[args.length];
         for (int i = 0; i < args.length; i++) {
             Value arg = args[i];
-            Value loc = cc.getArgument(i);
+            AllocatableValue loc = cc.getArgument(i);
             emitMove(loc, arg);
             argLocations[i] = loc;
         }
@@ -826,6 +826,10 @@
         return frameMap;
     }
 
+    @Override
+    public void beforeRegisterAllocation() {
+    }
+
     public abstract void emitBitCount(Variable result, Value operand);
 
     public abstract void emitBitScanForward(Variable result, Value operand);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.compiler.gen;
 
+import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.api.meta.Value.*;
 import static com.oracle.graal.lir.LIRValueUtil.*;
-import static com.oracle.graal.api.code.ValueUtil.*;
 
 import java.util.*;
 
@@ -187,7 +187,7 @@
     private void emitMove(Value dest, Value src) {
         assert isLegal(src);
         assert isLegal(dest);
-        gen.emitMove(dest, src);
+        gen.emitMove((AllocatableValue) dest, src);
     }
 
     // Traverse assignment graph in depth first order and generate moves in post order
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Sun Apr 28 22:52:12 2013 +0200
@@ -34,16 +34,10 @@
     public HighTier() {
         if (GraalOptions.FullUnroll) {
             addPhase(new LoopFullUnrollPhase());
-            if (GraalOptions.OptCanonicalizer) {
-                addPhase(new CanonicalizerPhase());
-            }
         }
 
         if (GraalOptions.OptTailDuplication) {
             addPhase(new TailDuplicationPhase());
-            if (GraalOptions.OptCanonicalizer) {
-                addPhase(new CanonicalizerPhase());
-            }
         }
 
         if (GraalOptions.PartialEscapeAnalysis) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraalInternalError.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraalInternalError.java	Sun Apr 28 22:52:12 2013 +0200
@@ -51,6 +51,23 @@
     }
 
     /**
+     * Checks a given condition and throws a {@link GraalInternalError} if it is false. Guarantees
+     * are stronger than assertions in that they are always checked. Error messages for guarantee
+     * violations should clearly indicate the nature of the problem as well as a suggested solution
+     * if possible.
+     * 
+     * @param condition the condition to check
+     * @param msg the message that will be associated with the error, in
+     *            {@link String#format(String, Object...)} syntax
+     * @param args arguments to the format string
+     */
+    public static void guarantee(boolean condition, String msg, Object... args) {
+        if (!condition) {
+            throw new GraalInternalError("failed guarantee: " + msg, args);
+        }
+    }
+
+    /**
      * This constructor creates a {@link GraalInternalError} with a message assembled via
      * {@link String#format(String, Object...)}. It always uses the ENGLISH locale in order to
      * always generate the same output.
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Sun Apr 28 22:52:12 2013 +0200
@@ -47,7 +47,8 @@
     private int deletedNodeCount;
     private GraphEventLog eventLog;
 
-    InputChangedListener inputChanged;
+    NodeChangedListener inputChanged;
+    NodeChangedListener usagesDroppedZero;
     private final HashMap<CacheEntry, Node> cachedNodes = new HashMap<>();
 
     private static final class CacheEntry {
@@ -152,12 +153,12 @@
         return node;
     }
 
-    public interface InputChangedListener {
+    public interface NodeChangedListener {
 
-        void inputChanged(Node node);
+        void nodeChanged(Node node);
     }
 
-    public void trackInputChange(InputChangedListener inputChangedListener) {
+    public void trackInputChange(NodeChangedListener inputChangedListener) {
         this.inputChanged = inputChangedListener;
     }
 
@@ -165,6 +166,14 @@
         inputChanged = null;
     }
 
+    public void trackUsagesDroppedZero(NodeChangedListener usagesDroppedZeroListener) {
+        this.usagesDroppedZero = usagesDroppedZeroListener;
+    }
+
+    public void stopTrackingUsagesDroppedZero() {
+        usagesDroppedZero = null;
+    }
+
     /**
      * Adds a new node to the graph, if a <i>similar</i> node already exists in the graph, the
      * provided node will not be added to the graph but the <i>similar</i> node will be returned
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Sun Apr 28 22:52:12 2013 +0200
@@ -25,7 +25,7 @@
 import java.lang.annotation.*;
 import java.util.*;
 
-import com.oracle.graal.graph.Graph.InputChangedListener;
+import com.oracle.graal.graph.Graph.NodeChangedListener;
 import com.oracle.graal.graph.NodeClass.*;
 import com.oracle.graal.graph.iterators.*;
 
@@ -193,12 +193,17 @@
                 assert assertTrue(result, "not found in usages, old input: %s", oldInput);
             }
             if (newInput != null) {
-                InputChangedListener inputChanged = graph.inputChanged;
+                NodeChangedListener inputChanged = graph.inputChanged;
                 if (inputChanged != null) {
-                    inputChanged.inputChanged(this);
+                    inputChanged.nodeChanged(this);
                 }
                 assert newInput.usages != null : "not yet added? " + newInput;
                 newInput.usages.add(this);
+            } else if (oldInput != null && oldInput.usages().isEmpty()) {
+                NodeChangedListener nodeChangedListener = graph.usagesDroppedZero;
+                if (nodeChangedListener != null) {
+                    nodeChangedListener.nodeChanged(oldInput);
+                }
             }
         }
     }
@@ -253,9 +258,9 @@
             boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
             assert assertTrue(result, "not found in inputs, usage: %s", usage);
             if (other != null) {
-                InputChangedListener inputChanged = graph.inputChanged;
+                NodeChangedListener inputChanged = graph.inputChanged;
                 if (inputChanged != null) {
-                    inputChanged.inputChanged(usage);
+                    inputChanged.nodeChanged(usage);
                 }
                 other.usages.add(usage);
             }
@@ -299,6 +304,12 @@
 
         for (Node input : inputs()) {
             removeThisFromUsages(input);
+            if (input.usages().isEmpty()) {
+                NodeChangedListener nodeChangedListener = graph.usagesDroppedZero;
+                if (nodeChangedListener != null) {
+                    nodeChangedListener.nodeChanged(input);
+                }
+            }
         }
         getNodeClass().clearInputs(this);
     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
@@ -49,7 +51,7 @@
 
     @Override
     public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-        HotSpotGraalRuntime runtime = HotSpotGraalRuntime.getInstance();
+        HotSpotGraalRuntime runtime = graalRuntime();
         Register thread = runtime.getRuntime().threadRegister();
         masm.movl(new AMD64Address(thread, runtime.getConfig().pendingDeoptimizationOffset), tasm.runtime.encodeDeoptActionAndReason(action, reason));
         AMD64Call.directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(DEOPTIMIZE), null, false, info);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Sun Apr 28 22:52:12 2013 +0200
@@ -45,6 +45,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.ParametersOp;
 import com.oracle.graal.lir.LIRInstruction.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
@@ -161,28 +162,59 @@
 
         Stub stub = runtime().asStub(lirGen.method());
         if (stub != null) {
-            final Set<Register> definedRegisters = new HashSet<>();
-            ValueProcedure defProc = new ValueProcedure() {
+
+            List<AMD64RegisterPreservationOp> registerPreservations = new ArrayList<>();
+            final Set<Register> definedRegisters = gatherDefinedRegisters(lir, registerPreservations);
+            stub.initDefinedRegisters(definedRegisters);
+
+            // Eliminate unnecessary register preservation
+            for (AMD64RegisterPreservationOp op : registerPreservations) {
+                op.doNotPreserve(definedRegisters);
+            }
+
+            // Record where preserved registers are saved
+            for (Map.Entry<LIRFrameState, AMD64RestoreRegistersOp> e : gen.calleeSaveInfo.entrySet()) {
+                e.getValue().describePreservation(e.getKey().debugInfo(), frameMap);
+            }
+        }
+
+        return tasm;
+    }
 
-                @Override
-                public Value doValue(Value value) {
-                    if (ValueUtil.isRegister(value)) {
-                        final Register reg = ValueUtil.asRegister(value);
-                        definedRegisters.add(reg);
-                    }
-                    return value;
+    /**
+     * Finds all the registers that are defined by some given LIR.
+     * 
+     * @param lir the LIR to examine
+     * @param registerPreservations register preservation operations in {@code lir} are added to this list
+     * @return the registers that are defined by or used as temps for any instruction in {@code lir}
+     */
+    private static Set<Register> gatherDefinedRegisters(LIR lir, List<AMD64RegisterPreservationOp> registerPreservations) {
+        final Set<Register> definedRegisters = new HashSet<>();
+        ValueProcedure defProc = new ValueProcedure() {
+
+            @Override
+            public Value doValue(Value value) {
+                if (ValueUtil.isRegister(value)) {
+                    final Register reg = ValueUtil.asRegister(value);
+                    definedRegisters.add(reg);
                 }
-            };
-            for (Block block : lir.codeEmittingOrder()) {
-                for (LIRInstruction op : lir.lir(block)) {
+                return value;
+            }
+        };
+        for (Block block : lir.codeEmittingOrder()) {
+            for (LIRInstruction op : lir.lir(block)) {
+                if (op instanceof AMD64RegisterPreservationOp) {
+                    // Don't consider these ops as definitions
+                    registerPreservations.add((AMD64RegisterPreservationOp) op);
+                } else if (op instanceof ParametersOp) {
+                    // Don't consider these ops as definitions
+                } else {
                     op.forEachTemp(defProc);
                     op.forEachOutput(defProc);
                 }
             }
-            stub.initDefinedRegisters(definedRegisters);
         }
-
-        return tasm;
+        return definedRegisters;
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallEpilogueOp.java	Sun Apr 28 22:52:12 2013 +0200
@@ -0,0 +1,52 @@
+/*
+ * 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.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+
+@Opcode("CRUNTIME_CALL_EPILOGUE")
+final class AMD64HotSpotCRuntimeCallEpilogueOp extends AMD64LIRInstruction {
+
+    @Use({REG, ILLEGAL}) protected Value thread;
+
+    AMD64HotSpotCRuntimeCallEpilogueOp(Value thread) {
+        this.thread = thread;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        // reset last Java frame:
+        HotSpotVMConfig config = graalRuntime().getConfig();
+        masm.movslq(new AMD64Address(asRegister(thread), config.threadLastJavaSpOffset), 0);
+        masm.movslq(new AMD64Address(asRegister(thread), config.threadLastJavaFpOffset), 0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallPrologueOp.java	Sun Apr 28 22:52:12 2013 +0200
@@ -0,0 +1,51 @@
+/*
+ * 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.amd64;
+
+import static com.oracle.graal.amd64.AMD64.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+
+@Opcode("CRUNTIME_CALL_PROLOGUE")
+final class AMD64HotSpotCRuntimeCallPrologueOp extends AMD64LIRInstruction {
+
+    @Use({REG, ILLEGAL}) protected Value thread;
+
+    AMD64HotSpotCRuntimeCallPrologueOp(Value thread) {
+        this.thread = thread;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+
+        // save last Java frame
+        masm.movq(new AMD64Address(asRegister(thread), graalRuntime().getConfig().threadLastJavaSpOffset), rsp);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Sun Apr 28 22:52:12 2013 +0200
@@ -0,0 +1,71 @@
+/*
+ * 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.amd64;
+
+import static com.oracle.graal.amd64.AMD64.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.amd64.AMD64DeoptimizeOp.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Removes the current frame and tail calls the uncommon trap routine.
+ */
+@Opcode("DEOPT_CALLER")
+final class AMD64HotSpotDeoptimizeCallerOp extends AMD64HotSpotEpilogueOp {
+
+    private final DeoptimizationAction action;
+    private final DeoptimizationReason reason;
+
+    AMD64HotSpotDeoptimizeCallerOp(DeoptimizationAction action, DeoptimizationReason reason) {
+        this.action = action;
+        this.reason = reason;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        if (isStackSlot(savedRbp)) {
+            // Restoring RBP from the stack must be done before the frame is removed
+            masm.movq(rbp, (AMD64Address) tasm.asAddress(savedRbp));
+        } else {
+            Register framePointer = asRegister(savedRbp);
+            if (framePointer != rbp) {
+                masm.movq(rbp, framePointer);
+            }
+        }
+        if (tasm.frameContext != null) {
+            tasm.frameContext.leave(tasm);
+        }
+        HotSpotGraalRuntime runtime = graalRuntime();
+        Register thread = runtime.getRuntime().threadRegister();
+        masm.movl(new AMD64Address(thread, runtime.getConfig().pendingDeoptimizationOffset), tasm.runtime.encodeDeoptActionAndReason(action, reason));
+        AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupRuntimeCall(DEOPTIMIZE));
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime.java	Sun Apr 28 22:52:12 2013 +0200
@@ -39,10 +39,10 @@
      * Called from C++ code to retrieve the singleton instance, creating it first if necessary.
      */
     public static HotSpotGraalRuntime makeInstance() {
-        if (getInstance() == null) {
+        if (graalRuntime() == null) {
             setInstance(new AMD64HotSpotGraalRuntime());
         }
-        return getInstance();
+        return graalRuntime();
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Sun Apr 28 22:52:12 2013 +0200
@@ -27,6 +27,7 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.hotspot.amd64.AMD64HotSpotUnwindOp.*;
 
+import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.amd64.*;
@@ -144,8 +145,8 @@
             }
         }
         params[params.length - 1] = rbpParam;
+        ParametersOp paramsOp = new ParametersOp(params);
 
-        ParametersOp paramsOp = new ParametersOp(params);
         append(paramsOp);
 
         saveRbp = new SaveRbp(new PlaceholderOp(currentBlock, lir.lir(currentBlock).size()));
@@ -171,6 +172,74 @@
         return runtime().asStub(method) != null;
     }
 
+    /**
+     * Map from debug infos that need to be updated with callee save information to the operations
+     * that provide the information.
+     */
+    Map<LIRFrameState, AMD64RestoreRegistersOp> calleeSaveInfo = new HashMap<>();
+
+    private LIRFrameState currentRuntimeCallInfo;
+
+    @Override
+    protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
+        boolean needsCalleeSave = ((HotSpotRuntimeCallTarget) callTarget).isCRuntimeCall();
+        if (needsCalleeSave) {
+            currentRuntimeCallInfo = info;
+        }
+        super.emitCall(callTarget, result, arguments, temps, info);
+    }
+
+    @Override
+    public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention cc, DeoptimizingNode info, Value... args) {
+        boolean needsCalleeSave = ((HotSpotRuntimeCallTarget) callTarget).isCRuntimeCall();
+
+        RegisterValue[] savedRegisters = null;
+        StackSlot[] savedRegisterLocations = null;
+        if (needsCalleeSave) {
+            Register returnReg = isRegister(cc.getReturn()) ? asRegister(cc.getReturn()) : null;
+            Set<Register> registers = new HashSet<>(Arrays.asList(frameMap.registerConfig.getAllocatableRegisters()));
+            if (returnReg != null) {
+                registers.remove(returnReg);
+            }
+
+            savedRegisters = new RegisterValue[registers.size()];
+            savedRegisterLocations = new StackSlot[savedRegisters.length];
+            int savedRegisterIndex = 0;
+            for (Register reg : registers) {
+                assert reg.isCpu() || reg.isFpu();
+                savedRegisters[savedRegisterIndex++] = reg.asValue(reg.isCpu() ? Kind.Long : Kind.Double);
+            }
+
+            append(new ParametersOp(savedRegisters));
+            for (int i = 0; i < savedRegisters.length; i++) {
+                StackSlot spillSlot = frameMap.allocateSpillSlot(Kind.Long);
+                savedRegisterLocations[i] = spillSlot;
+            }
+            AMD64SaveRegistersOp save = new AMD64SaveRegistersOp(savedRegisters, savedRegisterLocations);
+            append(save);
+
+            Value thread = args[0];
+            AMD64HotSpotCRuntimeCallPrologueOp op = new AMD64HotSpotCRuntimeCallPrologueOp(thread);
+            append(op);
+        }
+
+        Variable result = super.emitCall(callTarget, cc, info, args);
+
+        if (needsCalleeSave) {
+
+            Value thread = args[0];
+            AMD64HotSpotCRuntimeCallEpilogueOp op = new AMD64HotSpotCRuntimeCallEpilogueOp(thread);
+            append(op);
+
+            AMD64RestoreRegistersOp restore = new AMD64RestoreRegistersOp(savedRegisterLocations.clone(), savedRegisters.clone());
+            AMD64RestoreRegistersOp oldValue = calleeSaveInfo.put(currentRuntimeCallInfo, restore);
+            assert oldValue == null;
+            append(restore);
+        }
+
+        return result;
+    }
+
     @Override
     protected CallingConvention createCallingConvention() {
         Stub stub = runtime().asStub(method);
@@ -223,7 +292,6 @@
     @Override
     public void emitTailcall(Value[] args, Value address) {
         append(new AMD64TailcallOp(args, address));
-
     }
 
     @Override
@@ -234,6 +302,7 @@
         } else {
             assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special;
             HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target();
+            assert !Modifier.isAbstract(resolvedMethod.getModifiers()) : "Cannot make direct call to abstract method.";
             Constant metaspaceMethod = resolvedMethod.getMetaspaceMethodConstant();
             append(new AMD64HotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind, metaspaceMethod));
         }
@@ -241,9 +310,9 @@
 
     @Override
     protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        Value metaspaceMethod = AMD64.rbx.asValue();
+        AllocatableValue metaspaceMethod = AMD64.rbx.asValue();
         emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()));
-        Value targetAddress = AMD64.rax.asValue();
+        AllocatableValue targetAddress = AMD64.rax.asValue();
         emitMove(targetAddress, operand(callTarget.computedAddress()));
         append(new AMD64IndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState));
     }
@@ -263,6 +332,13 @@
     }
 
     @Override
+    public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
+        AMD64HotSpotDeoptimizeCallerOp op = new AMD64HotSpotDeoptimizeCallerOp(action, reason);
+        epilogueOps.add(op);
+        append(op);
+    }
+
+    @Override
     public void beforeRegisterAllocation() {
         boolean hasDebugInfo = lir.hasDebugInfo();
         AllocatableValue savedRbp = saveRbp.finalize(hasDebugInfo);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Sun Apr 28 22:52:12 2013 +0200
@@ -143,7 +143,7 @@
     }
 
     private CallingConvention callingConvention(Register[] generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, Type type, TargetDescription target, boolean stackOnly) {
-        Value[] locations = new Value[parameterTypes.length];
+        AllocatableValue[] locations = new AllocatableValue[parameterTypes.length];
 
         int currentGeneral = 0;
         int currentXMM = 0;
@@ -183,7 +183,7 @@
         }
 
         Kind returnKind = returnType == null ? Kind.Void : returnType.getKind();
-        Value returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(returnKind);
+        AllocatableValue returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(returnKind);
         return new CallingConvention(currentStackOffset, returnLocation, locations);
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java	Sun Apr 28 22:52:12 2013 +0200
@@ -33,7 +33,7 @@
 import com.oracle.graal.lir.asm.*;
 
 /**
- * Performs an unwind to throw an exception.
+ * Returns from a function.
  */
 @Opcode("RETURN")
 final class AMD64HotSpotReturnOp extends AMD64HotSpotEpilogueOp {
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Sun Apr 28 22:52:12 2013 +0200
@@ -29,9 +29,7 @@
 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.*;
 import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*;
-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.*;
@@ -43,6 +41,9 @@
 import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.EncryptBlockStubCall.*;
 import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.DecryptAESCryptStubCall.*;
 import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.EncryptAESCryptStubCall.*;
+import static com.oracle.graal.hotspot.stubs.NewArrayStub.*;
+import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*;
+import static com.oracle.graal.hotspot.stubs.NewMultiArrayStub.*;
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
@@ -110,28 +111,37 @@
                 /* arg0:    hub */ rdx.asValue(word),
                 /* arg1: length */ rbx.asValue(Kind.Int));
 
-        addRuntimeCall(NEW_ARRAY_SLOW, config.newArrayStub,
+        addRuntimeCall(NEW_ARRAY_C, config.newArrayAddress,
                 /*        temps */ null,
-                /*          ret */ rax.asValue(Kind.Object),
-                /* arg0:    hub */ rdx.asValue(word),
-                /* arg1: length */ rbx.asValue(Kind.Int));
+                /*          ret */ ret(Kind.Void),
+                /* arg0: thread */ nativeCallingConvention(word,
+                /* arg1:    hub */                         word,
+                /* arg2: length */                         Kind.Int));
 
         addStubCall(NEW_INSTANCE,
                 /*          ret */ rax.asValue(Kind.Object),
                 /* arg0:    hub */ rdx.asValue(word));
 
-        addRuntimeCall(NEW_INSTANCE_SLOW, config.newInstanceStub,
+        addRuntimeCall(NEW_INSTANCE_C, config.newInstanceAddress,
                 /*        temps */ null,
-                /*          ret */ rax.asValue(Kind.Object),
-                /* arg0:    hub */ rdx.asValue(word));
+                /*          ret */ ret(Kind.Void),
+                /* arg0: thread */ nativeCallingConvention(word,
+                /* arg1:    hub */                         word));
 
-        addRuntimeCall(NEW_MULTI_ARRAY, config.newMultiArrayStub,
-                /*        temps */ null,
+        addStubCall(NEW_MULTI_ARRAY,
                 /*          ret */ rax.asValue(Kind.Object),
                 /* arg0:    hub */ rax.asValue(word),
                 /* arg1:   rank */ rbx.asValue(Kind.Int),
                 /* arg2:   dims */ rcx.asValue(word));
 
+        addRuntimeCall(NEW_MULTI_ARRAY_C, config.newMultiArrayAddress,
+                /*        temps */ null,
+                /*          ret */ ret(Kind.Void),
+                /* arg0: thread */ nativeCallingConvention(word,
+                /* arg1:    hub */                         word,
+                /* arg2:   rank */                         Kind.Int,
+                /* arg3:   dims */                         word));
+
         addRuntimeCall(VERIFY_OOP, config.verifyOopStub,
                 /*        temps */ null,
                 /*          ret */ ret(Kind.Void),
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java	Sun Apr 28 22:52:12 2013 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.LIRInstruction.Opcode;
 import com.oracle.graal.lir.amd64.*;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64SafepointOp.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64SafepointOp.java	Sun Apr 28 22:52:12 2013 +0200
@@ -27,6 +27,7 @@
 import sun.misc.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.bridge.*;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotGraalRuntime.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotGraalRuntime.java	Sun Apr 28 22:52:12 2013 +0200
@@ -38,10 +38,10 @@
      * Called from C++ code to retrieve the singleton instance, creating it first if necessary.
      */
     public static HotSpotGraalRuntime makeInstance() {
-        if (getInstance() == null) {
+        if (graalRuntime() == null) {
             setInstance(new SPARCHotSpotGraalRuntime());
         }
-        return getInstance();
+        return graalRuntime();
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
 import java.io.File;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
@@ -50,7 +52,7 @@
     public static final String SUN_BOOT_CLASS_PATH = "sun.boot.class.path";
 
     // Some runtime instances we need.
-    private final HotSpotGraalRuntime graalRuntime = HotSpotGraalRuntime.getInstance();
+    private final HotSpotGraalRuntime graalRuntime = graalRuntime();
     private final VMToCompilerImpl vmToCompiler = (VMToCompilerImpl) graalRuntime.getVMToCompiler();
 
     /** List of Zip/Jar files to compile (see {@link GraalOptions#CompileTheWorld}. */
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerThread.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerThread.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
 import java.io.*;
 import java.util.concurrent.*;
 
@@ -59,7 +61,7 @@
     public void run() {
         GraalDebugConfig hotspotDebugConfig = null;
         if (GraalOptions.Debug) {
-            PrintStream log = HotSpotGraalRuntime.getInstance().getVMToCompiler().log();
+            PrintStream log = graalRuntime().getVMToCompiler().log();
             DebugEnvironment.initialize(log);
         }
         try {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompilationResult.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompilationResult.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,11 +22,17 @@
  */
 package com.oracle.graal.hotspot;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CompilationResult.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.code.CompilationResult.ExceptionHandler;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.replacements.*;
 
 /**
  * Augments a {@link CompilationResult} with HotSpot-specific information.
@@ -37,7 +43,12 @@
     public final CompilationResult comp;
     public final HotSpotResolvedJavaMethod method; // used only for methods
     public final int entryBCI; // used only for methods
-    public final String name; // used only for stubs
+
+    /**
+     * Name of the RuntimeStub to be installed for this compilation result. If null, then the
+     * compilation result will be installed as an nmethod.
+     */
+    public final String stubName;
 
     public final Site[] sites;
     public final ExceptionHandler[] exceptionHandlers;
@@ -46,7 +57,12 @@
         this.method = method;
         this.comp = comp;
         this.entryBCI = entryBCI;
-        this.name = null;
+
+        if (graalRuntime().getRuntime().lookupJavaType(Stub.class).isAssignableFrom(method.getDeclaringClass()) && method.getAnnotation(Snippet.class) != null) {
+            this.stubName = MetaUtil.format("%h.%n", method);
+        } else {
+            this.stubName = null;
+        }
 
         sites = getSortedSites(comp);
         if (comp.getExceptionHandlers() == null) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Sun Apr 28 22:52:12 2013 +0200
@@ -47,9 +47,9 @@
     private static HotSpotGraalRuntime instance;
 
     /**
-     * Gets the singleton runtime instance object.
+     * Gets the singleton {@link HotSpotGraalRuntime} object.
      */
-    public static HotSpotGraalRuntime getInstance() {
+    public static HotSpotGraalRuntime graalRuntime() {
         return instance;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Sun Apr 28 22:52:12 2013 +0200
@@ -42,6 +42,8 @@
      */
     void emitTailcall(Value[] args, Value address);
 
+    void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason);
+
     void visitDirectCompareAndSwap(DirectCompareAndSwapNode x);
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java	Sun Apr 28 22:52:12 2013 +0200
@@ -46,7 +46,7 @@
     private long address;
 
     /**
-     * Non-null (eventually) iff this is a call to a snippet-based {@linkplain Stub stub}.
+     * Non-null (eventually) iff this is a call to a compiled {@linkplain Stub stub}.
      */
     private Stub stub;
 
@@ -91,13 +91,13 @@
             assert stub != null : "linkage without an address must be a stub";
             InstalledCode code = stub.getCode(backend);
 
-            Value[] argumentLocations = new Value[cc.getArgumentCount()];
+            AllocatableValue[] argumentLocations = new AllocatableValue[cc.getArgumentCount()];
             for (int i = 0; i < argumentLocations.length; i++) {
                 argumentLocations[i] = cc.getArgument(i);
             }
 
             Set<Register> definedRegisters = stub.getDefinedRegisters();
-            Value[] temporaryLocations = new Value[definedRegisters.size()];
+            AllocatableValue[] temporaryLocations = new AllocatableValue[definedRegisters.size()];
             int i = 0;
             for (Register reg : definedRegisters) {
                 temporaryLocations[i++] = reg.asValue();
@@ -113,4 +113,12 @@
         assert address != 0;
         return true;
     }
+
+    /**
+     * Determines if this is a link to a C/C++ function in the HotSpot runtime.
+     */
+    public boolean isCRuntimeCall() {
+        HotSpotVMConfig config = HotSpotGraalRuntime.graalRuntime().getConfig();
+        return address == config.newArrayAddress || address == config.newInstanceAddress || address == config.newMultiArrayAddress;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Sun Apr 28 22:52:12 2013 +0200
@@ -179,6 +179,11 @@
     public int uninitializedIdentityHashCodeValue;
 
     /**
+     * Offset of the pending exception field.
+     */
+    public int pendingExceptionOffset;
+
+    /**
      * Offset of the pending deoptimization field.
      */
     public int pendingDeoptimizationOffset;
@@ -302,6 +307,10 @@
     public int threadTlabStartOffset;
     public int threadTlabSizeOffset;
     public int threadAllocatedBytesOffset;
+    public int threadLastJavaSpOffset;
+    public int threadLastJavaFpOffset;
+    public int threadLastJavaPcOffset;
+    public int threadObjectResultOffset;
     public int tlabRefillWasteLimitOffset;
     public int tlabRefillWasteIncrement;
     public int tlabAlignmentReserve;
@@ -334,9 +343,6 @@
     public int typeProfileWidth;
 
     // runtime stubs
-    public long newInstanceStub;
-    public long newArrayStub;
-    public long newMultiArrayStub;
     public long inlineCacheMissStub;
     public long handleExceptionStub;
     public long handleDeoptStub;
@@ -372,6 +378,10 @@
     public long cipherBlockChainingEncryptAESCryptStub;
     public long cipherBlockChainingDecryptAESCryptStub;
 
+    public long newInstanceAddress;
+    public long newArrayAddress;
+    public long newMultiArrayAddress;
+
     public int deoptReasonNullCheck;
     public int deoptReasonRangeCheck;
     public int deoptReasonClassCheck;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Sun Apr 28 22:52:12 2013 +0200
@@ -194,20 +194,20 @@
 
     long getMaxCallTargetOffset(long stub);
 
-    String disassembleNMethod(long nmethod);
+    String disassembleCodeBlob(long codeBlob);
 
     /**
-     * Gets a copy of the machine code for an nmethod.
+     * Gets a copy of the machine code for a CodeBlob.
      * 
-     * @return the machine code for {@code nmethod} if it is valid, null otherwise
+     * @return the machine code for {@code codeBlob} if it is valid, null otherwise
      */
-    byte[] getCode(long nmethod);
+    byte[] getCode(long codeBlob);
 
     StackTraceElement getStackTraceElement(long metaspaceMethod, int bci);
 
-    Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nativeMethod) throws InvalidInstalledCodeException;
+    Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nmethod) throws InvalidInstalledCodeException;
 
-    Object executeCompiledMethodVarargs(Object[] args, long nativeMethod) throws InvalidInstalledCodeException;
+    Object executeCompiledMethodVarargs(Object[] args, long nmethod) throws InvalidInstalledCodeException;
 
     int getVtableEntryOffset(long metaspaceMethod);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Sun Apr 28 22:52:12 2013 +0200
@@ -130,16 +130,16 @@
     public native long getMaxCallTargetOffset(long stub);
 
     @Override
-    public native String disassembleNMethod(long nmethod);
+    public native String disassembleCodeBlob(long codeBlob);
 
     @Override
-    public native byte[] getCode(long nmethod);
+    public native byte[] getCode(long codeBlob);
 
     @Override
     public native StackTraceElement getStackTraceElement(long metaspaceMethod, int bci);
 
     @Override
-    public native Object executeCompiledMethodVarargs(Object[] args, long nativeMethod);
+    public native Object executeCompiledMethodVarargs(Object[] args, long nmethod);
 
     @Override
     public native int getVtableEntryOffset(long metaspaceMethod);
@@ -172,16 +172,16 @@
     public native boolean isInstalledCodeValid(long nativeMethod);
 
     @Override
-    public Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nativeMethod) throws InvalidInstalledCodeException {
-        return executeCompiledMethodIntrinsic(arg1, arg2, arg3, nativeMethod);
+    public Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nmethod) throws InvalidInstalledCodeException {
+        return executeCompiledMethodIntrinsic(arg1, arg2, arg3, nmethod);
     }
 
     /**
-     * Direct call to the given nativeMethod with three object arguments and an object return value.
-     * This method does not have an implementation on the C++ side, but its entry points (from
+     * Direct call to the given nmethod with three object arguments and an object return value. This
+     * method does not have an implementation on the C++ side, but its entry points (from
      * interpreter and from compiled code) are directly pointing to a manually generated assembly
      * stub that does the necessary argument shuffling and a tail call via an indirect jump to the
      * verified entry point of the given native method.
      */
-    private static native Object executeCompiledMethodIntrinsic(Object arg1, Object arg2, Object arg3, long nativeMethod);
+    private static native Object executeCompiledMethodIntrinsic(Object arg1, Object arg2, Object arg3, long nmethod);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Sun Apr 28 22:52:12 2013 +0200
@@ -25,6 +25,7 @@
 
 import static com.oracle.graal.graph.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.CompilationTask.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.java.GraphBuilderPhase.*;
 import static com.oracle.graal.phases.common.InliningUtil.*;
 
@@ -686,7 +687,7 @@
     public HotSpotResolvedObjectType createResolvedJavaType(long metaspaceKlass, String name, String simpleName, Class javaMirror, int sizeOrSpecies) {
         HotSpotResolvedObjectType type = new HotSpotResolvedObjectType(metaspaceKlass, name, simpleName, javaMirror, sizeOrSpecies);
 
-        long offset = HotSpotGraalRuntime.getInstance().getConfig().graalMirrorInClassOffset;
+        long offset = graalRuntime().getConfig().graalMirrorInClassOffset;
         if (!unsafe.compareAndSwapObject(javaMirror, offset, null, type)) {
             // lost the race - return the existing value instead
             type = (HotSpotResolvedObjectType) unsafe.getObject(javaMirror, offset);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalImpl.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalImpl.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.hotspot.debug;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 
 public class LocalImpl implements Local {
@@ -39,9 +40,9 @@
         this.bciStart = bciStart;
         this.bciEnd = bciEnd;
         this.slot = slot;
-        JavaType t = HotSpotGraalRuntime.getInstance().lookupType(type, holder, true);
+        JavaType t = graalRuntime().lookupType(type, holder, true);
         if (t instanceof ResolvedJavaType) {
-            this.resolvedType = (ResolvedJavaType) HotSpotGraalRuntime.getInstance().lookupType(type, holder, false);
+            this.resolvedType = (ResolvedJavaType) graalRuntime().lookupType(type, holder, false);
         } else {
             throw new AssertionError(t.getClass() + " is not a ResolvedJavaType");
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.meta;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.bytecode.*;
 import com.oracle.graal.hotspot.*;
@@ -41,13 +43,13 @@
 
     @Override
     public int length() {
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().constantPoolLength(type);
+        return graalRuntime().getCompilerToVM().constantPoolLength(type);
     }
 
     @Override
     public Object lookupConstant(int cpi) {
         assert cpi != 0;
-        Object constant = HotSpotGraalRuntime.getInstance().getCompilerToVM().lookupConstantInPool(type, cpi);
+        Object constant = graalRuntime().getCompilerToVM().lookupConstantInPool(type, cpi);
         return constant;
     }
 
@@ -59,26 +61,26 @@
     @Override
     public Object lookupAppendix(int cpi, int opcode) {
         assert Bytecodes.isInvoke(opcode);
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().lookupAppendixInPool(type, cpi, (byte) opcode);
+        return graalRuntime().getCompilerToVM().lookupAppendixInPool(type, cpi, (byte) opcode);
     }
 
     @Override
     public JavaMethod lookupMethod(int cpi, int opcode) {
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().lookupMethodInPool(type, cpi, (byte) opcode);
+        return graalRuntime().getCompilerToVM().lookupMethodInPool(type, cpi, (byte) opcode);
     }
 
     @Override
     public JavaType lookupType(int cpi, int opcode) {
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().lookupTypeInPool(type, cpi);
+        return graalRuntime().getCompilerToVM().lookupTypeInPool(type, cpi);
     }
 
     @Override
     public JavaField lookupField(int cpi, int opcode) {
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().lookupFieldInPool(type, cpi, (byte) opcode);
+        return graalRuntime().getCompilerToVM().lookupFieldInPool(type, cpi, (byte) opcode);
     }
 
     @Override
     public void loadReferencedType(int cpi, int opcode) {
-        HotSpotGraalRuntime.getInstance().getCompilerToVM().lookupReferencedTypeInPool(type, cpi, (byte) opcode);
+        graalRuntime().getCompilerToVM().lookupReferencedTypeInPool(type, cpi, (byte) opcode);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.meta;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
 import java.lang.reflect.*;
 
 import com.oracle.graal.api.code.*;
@@ -41,8 +43,9 @@
     private final HotSpotResolvedJavaMethod method;
     private final boolean isDefault;
     private final Graph graph;
-    long nmethod;
+    long codeBlob;
     long start;
+    boolean isNmethod;
 
     public HotSpotInstalledCode(HotSpotResolvedJavaMethod method, Graph graph, boolean isDefault) {
         this.method = method;
@@ -54,8 +57,8 @@
         return isDefault;
     }
 
-    public long getMethodAddress() {
-        return nmethod;
+    public long getCodeBlob() {
+        return codeBlob;
     }
 
     public Graph getGraph() {
@@ -69,26 +72,29 @@
 
     @Override
     public boolean isValid() {
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().isInstalledCodeValid(nmethod);
+        return !isNmethod || graalRuntime().getCompilerToVM().isInstalledCodeValid(codeBlob);
     }
 
     @Override
     public void invalidate() {
-        HotSpotGraalRuntime.getInstance().getCompilerToVM().invalidateInstalledCode(nmethod);
+        if (isNmethod) {
+            graalRuntime().getCompilerToVM().invalidateInstalledCode(codeBlob);
+        }
     }
 
     @Override
     public String toString() {
-        return String.format("InstalledCode[method=%s, nmethod=0x%x]", method, nmethod);
+        return String.format("InstalledCode[method=%s, codeBlob=0x%x]", method, codeBlob);
     }
 
     @Override
     public Object execute(Object arg1, Object arg2, Object arg3) throws InvalidInstalledCodeException {
+        assert isNmethod;
         assert method.getSignature().getParameterCount(!Modifier.isStatic(method.getModifiers())) == 3;
         assert method.getSignature().getParameterKind(0) == Kind.Object;
         assert method.getSignature().getParameterKind(1) == Kind.Object;
         assert !Modifier.isStatic(method.getModifiers()) || method.getSignature().getParameterKind(2) == Kind.Object;
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().executeCompiledMethod(arg1, arg2, arg3, nmethod);
+        return graalRuntime().getCompilerToVM().executeCompiledMethod(arg1, arg2, arg3, codeBlob);
     }
 
     private boolean checkArgs(Object... args) {
@@ -107,8 +113,9 @@
 
     @Override
     public Object executeVarargs(Object... args) throws InvalidInstalledCodeException {
+        assert isNmethod;
         assert checkArgs(args);
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().executeCompiledMethodVarargs(args, nmethod);
+        return graalRuntime().getCompilerToVM().executeCompiledMethodVarargs(args, codeBlob);
     }
 
     @Override
@@ -118,6 +125,6 @@
 
     @Override
     public byte[] getCode() {
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().getCode(nmethod);
+        return graalRuntime().getCompilerToVM().getCode(codeBlob);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Sun Apr 28 22:52:12 2013 +0200
@@ -40,7 +40,7 @@
 
     private static final long serialVersionUID = -8873133496591225071L;
 
-    private static final HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig();
+    private static final HotSpotVMConfig config = graalRuntime().getConfig();
     private static final HotSpotMethodDataAccessor NO_DATA_NO_EXCEPTION_ACCESSOR = new NoMethodData(TriState.FALSE);
     private static final HotSpotMethodDataAccessor NO_DATA_EXCEPTION_POSSIBLY_NOT_RECORDED_ACCESSOR = new NoMethodData(TriState.UNKNOWN);
 
@@ -58,7 +58,7 @@
 
     HotSpotMethodData(long metaspaceMethodData) {
         this.metaspaceMethodData = metaspaceMethodData;
-        HotSpotGraalRuntime.getInstance().getCompilerToVM().initializeMethodData(metaspaceMethodData, this);
+        graalRuntime().getCompilerToVM().initializeMethodData(metaspaceMethodData, this);
     }
 
     public boolean hasNormalData() {
@@ -78,7 +78,7 @@
     }
 
     public int getDeoptimizationCount(DeoptimizationReason reason) {
-        int reasonIndex = HotSpotGraalRuntime.getInstance().getRuntime().convertDeoptReason(reason);
+        int reasonIndex = graalRuntime().getRuntime().convertDeoptReason(reason);
         return unsafe.getByte(metaspaceMethodData + config.methodDataOopTrapHistoryOffset + reasonIndex) & 0xFF;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Sun Apr 28 22:52:12 2013 +0200
@@ -24,6 +24,7 @@
 package com.oracle.graal.hotspot.meta;
 
 import static com.oracle.graal.api.meta.MetaUtil.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.lang.annotation.*;
 import java.lang.reflect.*;
@@ -109,12 +110,12 @@
         if (receiver == null) {
             assert Modifier.isStatic(flags);
             if (holder.isInitialized()) {
-                return HotSpotGraalRuntime.getInstance().getRuntime().readUnsafeConstant(getKind(), holder.mirror(), offset);
+                return graalRuntime().getRuntime().readUnsafeConstant(getKind(), holder.mirror(), offset);
             }
             return null;
         } else {
             assert !Modifier.isStatic(flags);
-            return HotSpotGraalRuntime.getInstance().getRuntime().readUnsafeConstant(getKind(), receiver.asObject(), offset);
+            return graalRuntime().getRuntime().readUnsafeConstant(getKind(), receiver.asObject(), offset);
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Sun Apr 28 22:52:12 2013 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.meta;
 
 import static com.oracle.graal.api.meta.MetaUtil.*;
-import static com.oracle.graal.graph.FieldIntrospection.*;
+import static com.oracle.graal.graph.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.lang.annotation.*;
@@ -66,7 +66,7 @@
     HotSpotResolvedJavaMethod(HotSpotResolvedObjectType holder, long metaspaceMethod) {
         this.metaspaceMethod = metaspaceMethod;
         this.holder = holder;
-        HotSpotGraalRuntime.getInstance().getCompilerToVM().initializeMethod(metaspaceMethod, this);
+        graalRuntime().getCompilerToVM().initializeMethod(metaspaceMethod, this);
     }
 
     @Override
@@ -82,12 +82,17 @@
      * Gets the address of the C++ Method object for this method.
      */
     public Constant getMetaspaceMethodConstant() {
-        return Constant.forIntegerKind(HotSpotGraalRuntime.getInstance().getTarget().wordKind, metaspaceMethod, this);
+        return Constant.forIntegerKind(graalRuntime().getTarget().wordKind, metaspaceMethod, this);
+    }
+
+    @Override
+    public Constant getEncoding() {
+        return getMetaspaceMethodConstant();
     }
 
     @Override
     public int getModifiers() {
-        HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig();
+        HotSpotVMConfig config = graalRuntime().getConfig();
         return unsafe.getInt(metaspaceMethod + config.methodAccessFlagsOffset) & Modifier.methodModifiers();
     }
 
@@ -103,7 +108,7 @@
             return null;
         }
         if (code == null) {
-            code = HotSpotGraalRuntime.getInstance().getCompilerToVM().initializeBytecode(metaspaceMethod, new byte[codeSize]);
+            code = graalRuntime().getCompilerToVM().initializeBytecode(metaspaceMethod, new byte[codeSize]);
             assert code.length == codeSize : "expected: " + codeSize + ", actual: " + code.length;
         }
         return code;
@@ -123,12 +128,12 @@
         for (int i = 0; i < exceptionHandlerCount; i++) {
             handlers[i] = new ExceptionHandler(-1, -1, -1, -1, null);
         }
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().initializeExceptionHandlers(metaspaceMethod, handlers);
+        return graalRuntime().getCompilerToVM().initializeExceptionHandlers(metaspaceMethod, handlers);
     }
 
     public boolean hasBalancedMonitors() {
         if (hasBalancedMonitors == null) {
-            hasBalancedMonitors = HotSpotGraalRuntime.getInstance().getCompilerToVM().hasBalancedMonitors(metaspaceMethod);
+            hasBalancedMonitors = graalRuntime().getCompilerToVM().hasBalancedMonitors(metaspaceMethod);
         }
         return hasBalancedMonitors;
     }
@@ -145,14 +150,14 @@
 
     @Override
     public int getMaxLocals() {
-        HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig();
+        HotSpotVMConfig config = graalRuntime().getConfig();
         long metaspaceConstMethod = unsafe.getLong(metaspaceMethod + config.methodConstMethodOffset);
         return unsafe.getShort(metaspaceConstMethod + config.methodMaxLocalsOffset) & 0xFFFF;
     }
 
     @Override
     public int getMaxStackSize() {
-        HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig();
+        HotSpotVMConfig config = graalRuntime().getConfig();
         long metaspaceConstMethod = unsafe.getLong(metaspaceMethod + config.methodConstMethodOffset);
         return config.extraStackEntries + (unsafe.getShort(metaspaceConstMethod + config.constMethodMaxStackOffset) & 0xFFFF);
     }
@@ -161,15 +166,15 @@
     public StackTraceElement asStackTraceElement(int bci) {
         if (bci < 0 || bci >= codeSize) {
             // HotSpot code can only construct stack trace elements for valid bcis
-            StackTraceElement ste = HotSpotGraalRuntime.getInstance().getCompilerToVM().getStackTraceElement(metaspaceMethod, 0);
+            StackTraceElement ste = graalRuntime().getCompilerToVM().getStackTraceElement(metaspaceMethod, 0);
             return new StackTraceElement(ste.getClassName(), ste.getMethodName(), ste.getFileName(), -1);
         }
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().getStackTraceElement(metaspaceMethod, bci);
+        return graalRuntime().getCompilerToVM().getStackTraceElement(metaspaceMethod, bci);
     }
 
     public ResolvedJavaMethod uniqueConcreteMethod() {
         HotSpotResolvedObjectType[] resultHolder = {null};
-        long ucm = HotSpotGraalRuntime.getInstance().getCompilerToVM().getUniqueConcreteMethod(metaspaceMethod, resultHolder);
+        long ucm = graalRuntime().getCompilerToVM().getUniqueConcreteMethod(metaspaceMethod, resultHolder);
         if (ucm != 0L) {
             assert resultHolder[0] != null;
             return resultHolder[0].createMethod(ucm);
@@ -180,7 +185,7 @@
     @Override
     public HotSpotSignature getSignature() {
         if (signature == null) {
-            signature = new HotSpotSignature(HotSpotGraalRuntime.getInstance().getCompilerToVM().getSignature(metaspaceMethod));
+            signature = new HotSpotSignature(graalRuntime().getCompilerToVM().getSignature(metaspaceMethod));
         }
         return signature;
     }
@@ -191,11 +196,11 @@
     }
 
     public int getCompiledCodeSize() {
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().getCompiledCodeSize(metaspaceMethod);
+        return graalRuntime().getCompilerToVM().getCompiledCodeSize(metaspaceMethod);
     }
 
     public int invocationCount() {
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().getInvocationCount(metaspaceMethod);
+        return graalRuntime().getCompilerToVM().getInvocationCount(metaspaceMethod);
     }
 
     @Override
@@ -219,7 +224,7 @@
         ProfilingInfo info;
 
         if (GraalOptions.UseProfilingInformation && methodData == null) {
-            long metaspaceMethodData = unsafeReadWord(metaspaceMethod + HotSpotGraalRuntime.getInstance().getConfig().methodDataOffset);
+            long metaspaceMethodData = unsafeReadWord(metaspaceMethod + graalRuntime().getConfig().methodDataOffset);
             if (metaspaceMethodData != 0) {
                 methodData = new HotSpotMethodData(metaspaceMethodData);
             }
@@ -237,7 +242,7 @@
 
     @Override
     public void reprofile() {
-        HotSpotGraalRuntime.getInstance().getCompilerToVM().reprofile(metaspaceMethod);
+        graalRuntime().getCompilerToVM().reprofile(metaspaceMethod);
     }
 
     @Override
@@ -311,12 +316,12 @@
 
     @Override
     public boolean canBeInlined() {
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().isMethodCompilable(metaspaceMethod);
+        return graalRuntime().getCompilerToVM().isMethodCompilable(metaspaceMethod);
     }
 
     @Override
     public LineNumberTable getLineNumberTable() {
-        long[] values = HotSpotGraalRuntime.getInstance().getCompilerToVM().getLineNumberTable(this);
+        long[] values = graalRuntime().getCompilerToVM().getLineNumberTable(this);
         assert values.length % 2 == 0;
         int[] bci = new int[values.length / 2];
         int[] line = new int[values.length / 2];
@@ -331,7 +336,7 @@
 
     @Override
     public LocalVariableTable getLocalVariableTable() {
-        Local[] locals = HotSpotGraalRuntime.getInstance().getCompilerToVM().getLocalVariableTable(this);
+        Local[] locals = graalRuntime().getCompilerToVM().getLocalVariableTable(this);
         return new LocalVariableTableImpl(locals);
     }
 
@@ -345,7 +350,7 @@
         if (!holder.isInitialized()) {
             return -1;
         }
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().getVtableEntryOffset(metaspaceMethod);
+        return graalRuntime().getCompilerToVM().getVtableEntryOffset(metaspaceMethod);
     }
 
     public void setCurrentTask(CompilationTask task) {
@@ -364,7 +369,7 @@
     }
 
     public int intrinsicId() {
-        HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig();
+        HotSpotVMConfig config = graalRuntime().getConfig();
         return unsafe.getByte(metaspaceMethod + config.methodIntrinsicIdOffset) & 0xff;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.hotspot.meta;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.hotspot.*;
 
 public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements ResolvedJavaType {
 
@@ -37,6 +38,6 @@
 
     @Override
     public String getSourceFileName() {
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().getFileName(this);
+        return graalRuntime().getCompilerToVM().getFileName(this);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Sun Apr 28 22:52:12 2013 +0200
@@ -98,7 +98,7 @@
      */
     public static ResolvedJavaType fromMetaspaceKlass(long metaspaceKlass) {
         assert metaspaceKlass != 0;
-        Class javaClass = (Class) unsafe.getObject(null, metaspaceKlass + HotSpotGraalRuntime.getInstance().getConfig().classMirrorOffset);
+        Class javaClass = (Class) unsafe.getObject(null, metaspaceKlass + graalRuntime().getConfig().classMirrorOffset);
         assert javaClass != null;
         return fromClass(javaClass);
     }
@@ -110,9 +110,9 @@
      */
     public static ResolvedJavaType fromClass(Class javaClass) {
         assert javaClass != null;
-        ResolvedJavaType type = (ResolvedJavaType) unsafe.getObject(javaClass, (long) HotSpotGraalRuntime.getInstance().getConfig().graalMirrorInClassOffset);
+        ResolvedJavaType type = (ResolvedJavaType) unsafe.getObject(javaClass, (long) graalRuntime().getConfig().graalMirrorInClassOffset);
         if (type == null) {
-            type = HotSpotGraalRuntime.getInstance().getCompilerToVM().getResolvedType(javaClass);
+            type = graalRuntime().getCompilerToVM().getResolvedType(javaClass);
             assert type != null;
         }
         return type;
@@ -140,7 +140,7 @@
     }
 
     public int getAccessFlags() {
-        HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig();
+        HotSpotVMConfig config = graalRuntime().getConfig();
         return unsafe.getInt(metaspaceKlass + config.klassAccessFlagsOffset);
     }
 
@@ -160,11 +160,11 @@
 
     @Override
     public ResolvedJavaType findUniqueConcreteSubtype() {
-        HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig();
+        HotSpotVMConfig config = graalRuntime().getConfig();
         if (isArray()) {
             return isFinal(getElementalType(this).getModifiers()) ? this : null;
         } else if (isInterface()) {
-            return HotSpotGraalRuntime.getInstance().getCompilerToVM().getUniqueImplementor(this);
+            return graalRuntime().getCompilerToVM().getUniqueImplementor(this);
         } else {
             HotSpotResolvedObjectType type = this;
             while (isAbstract(type.getModifiers())) {
@@ -258,12 +258,12 @@
     @Override
     public boolean hasFinalizableSubclass() {
         assert !isArray();
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().hasFinalizableSubclass(this);
+        return graalRuntime().getCompilerToVM().hasFinalizableSubclass(this);
     }
 
     @Override
     public boolean hasFinalizer() {
-        HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig();
+        HotSpotVMConfig config = graalRuntime().getConfig();
         return (getAccessFlags() & config.klassHasFinalizerFlag) != 0;
     }
 
@@ -280,7 +280,7 @@
     @Override
     public boolean isInitialized() {
         if (!isInitialized) {
-            isInitialized = HotSpotGraalRuntime.getInstance().getCompilerToVM().isTypeInitialized(this);
+            isInitialized = graalRuntime().getCompilerToVM().isTypeInitialized(this);
         }
         return isInitialized;
     }
@@ -288,7 +288,7 @@
     @Override
     public void initialize() {
         if (!isInitialized) {
-            HotSpotGraalRuntime.getInstance().getCompilerToVM().initializeType(this);
+            graalRuntime().getCompilerToVM().initializeType(this);
         }
         isInitialized = true;
     }
@@ -328,7 +328,7 @@
     @Override
     public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method) {
         assert method instanceof HotSpotMethod;
-        return (ResolvedJavaMethod) HotSpotGraalRuntime.getInstance().getCompilerToVM().resolveMethod(this, method.getName(), ((HotSpotSignature) method.getSignature()).getMethodDescriptor());
+        return (ResolvedJavaMethod) graalRuntime().getCompilerToVM().resolveMethod(this, method.getName(), ((HotSpotSignature) method.getSignature()).getMethodDescriptor());
     }
 
     @Override
@@ -411,7 +411,7 @@
             if (isArray() || isInterface()) {
                 instanceFields = new HotSpotResolvedJavaField[0];
             } else {
-                HotSpotResolvedJavaField[] myFields = HotSpotGraalRuntime.getInstance().getCompilerToVM().getInstanceFields(this);
+                HotSpotResolvedJavaField[] myFields = graalRuntime().getCompilerToVM().getInstanceFields(this);
                 Arrays.sort(myFields, new OffsetComparator());
                 if (javaMirror != Object.class) {
                     HotSpotResolvedJavaField[] superFields = (HotSpotResolvedJavaField[]) getSuperclass().getInstanceFields(true);
@@ -447,7 +447,7 @@
 
     @Override
     public String getSourceFileName() {
-        return HotSpotGraalRuntime.getInstance().getCompilerToVM().getFileName(this);
+        return graalRuntime().getCompilerToVM().getFileName(this);
     }
 
     @Override
@@ -464,20 +464,20 @@
      * Gets the address of the C++ Klass object for this type.
      */
     public Constant klass() {
-        return Constant.forIntegerKind(HotSpotGraalRuntime.getInstance().getTarget().wordKind, metaspaceKlass, this);
+        return Constant.forIntegerKind(graalRuntime().getTarget().wordKind, metaspaceKlass, this);
     }
 
     public boolean isPrimaryType() {
-        return HotSpotGraalRuntime.getInstance().getConfig().secondarySuperCacheOffset != superCheckOffset();
+        return graalRuntime().getConfig().secondarySuperCacheOffset != superCheckOffset();
     }
 
     public int superCheckOffset() {
-        HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig();
+        HotSpotVMConfig config = graalRuntime().getConfig();
         return unsafe.getInt(metaspaceKlass + config.superCheckOffsetOffset);
     }
 
     public long prototypeMarkWord() {
-        HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig();
+        HotSpotVMConfig config = graalRuntime().getConfig();
         if (isArray()) {
             return config.arrayPrototypeMarkWord;
         } else {
@@ -523,7 +523,7 @@
         Constructor[] constructors = javaMirror.getDeclaredConstructors();
         ResolvedJavaMethod[] result = new ResolvedJavaMethod[constructors.length];
         for (int i = 0; i < constructors.length; i++) {
-            result[i] = HotSpotGraalRuntime.getInstance().getRuntime().lookupJavaConstructor(constructors[i]);
+            result[i] = graalRuntime().getRuntime().lookupJavaConstructor(constructors[i]);
             assert result[i].isConstructor();
         }
         return result;
@@ -534,7 +534,7 @@
         Method[] methods = javaMirror.getDeclaredMethods();
         ResolvedJavaMethod[] result = new ResolvedJavaMethod[methods.length];
         for (int i = 0; i < methods.length; i++) {
-            result[i] = HotSpotGraalRuntime.getInstance().getRuntime().lookupJavaMethod(methods[i]);
+            result[i] = graalRuntime().getRuntime().lookupJavaMethod(methods[i]);
             assert !result[i].isConstructor();
         }
         return result;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Sun Apr 28 22:52:12 2013 +0200
@@ -32,7 +32,9 @@
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*;
 import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*;
+import static com.oracle.graal.hotspot.nodes.NewMultiArrayStubCall.*;
 import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*;
+import static com.oracle.graal.hotspot.stubs.Stub.*;
 import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*;
 import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*;
 import static com.oracle.graal.replacements.Log.*;
@@ -47,8 +49,8 @@
 import com.oracle.graal.api.code.CodeUtil.RefMapFormatter;
 import com.oracle.graal.api.code.CompilationResult.Call;
 import com.oracle.graal.api.code.CompilationResult.DataPatch;
+import com.oracle.graal.api.code.CompilationResult.Infopoint;
 import com.oracle.graal.api.code.CompilationResult.Mark;
-import com.oracle.graal.api.code.CompilationResult.Infopoint;
 import com.oracle.graal.api.code.Register.RegisterFlag;
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
@@ -163,23 +165,23 @@
         }
     }
 
-    protected Value ret(Kind kind) {
+    protected AllocatableValue ret(Kind kind) {
         if (kind == Kind.Void) {
             return ILLEGAL;
         }
         return globalStubRegConfig.getReturnRegister(kind).asValue(kind);
     }
 
-    protected Value[] javaCallingConvention(Kind... arguments) {
+    protected AllocatableValue[] javaCallingConvention(Kind... arguments) {
         return callingConvention(arguments, RuntimeCall);
     }
 
-    protected Value[] nativeCallingConvention(Kind... arguments) {
+    protected AllocatableValue[] nativeCallingConvention(Kind... arguments) {
         return callingConvention(arguments, NativeCall);
     }
 
-    private Value[] callingConvention(Kind[] arguments, CallingConvention.Type type) {
-        Value[] result = new Value[arguments.length];
+    private AllocatableValue[] callingConvention(Kind[] arguments, CallingConvention.Type type) {
+        AllocatableValue[] result = new AllocatableValue[arguments.length];
 
         TargetDescription target = graalRuntime.getTarget();
         int currentStackOffset = 0;
@@ -262,7 +264,7 @@
                         /* arg2:     value */                       Kind.Long,
                         /* arg3:     value */                       Kind.Long));
 
-        addRuntimeCall(Stub.STUB_PRINTF, config.stubPrintfStub,
+        addRuntimeCall(STUB_PRINTF, config.stubPrintfStub,
                         /*           temps */ null,
                         /*             ret */ ret(Kind.Void),
                         /* arg0:    format */ javaCallingConvention(Kind.Long,
@@ -285,7 +287,7 @@
      * @param ret where the call returns its result
      * @param args where arguments are passed to the call
      */
-    protected RuntimeCallTarget addStubCall(Descriptor descriptor, Value ret, Value... args) {
+    protected RuntimeCallTarget addStubCall(Descriptor descriptor, AllocatableValue ret, AllocatableValue... args) {
         return addRuntimeCall(descriptor, 0L, null, ret, args);
     }
 
@@ -298,8 +300,8 @@
      * @param ret where the call returns its result
      * @param args where arguments are passed to the call
      */
-    protected RuntimeCallTarget addRuntimeCall(Descriptor descriptor, long address, Register[] tempRegs, Value ret, Value... args) {
-        Value[] temps = tempRegs == null || tempRegs.length == 0 ? Value.NONE : new Value[tempRegs.length];
+    protected RuntimeCallTarget addRuntimeCall(Descriptor descriptor, long address, Register[] tempRegs, AllocatableValue ret, AllocatableValue... args) {
+        AllocatableValue[] temps = tempRegs == null || tempRegs.length == 0 ? AllocatableValue.NONE : new AllocatableValue[tempRegs.length];
         for (int i = 0; i < temps.length; i++) {
             temps[i] = tempRegs[i].asValue();
         }
@@ -358,6 +360,7 @@
 
         registerStub(new NewInstanceStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_INSTANCE)));
         registerStub(new NewArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_ARRAY)));
+        registerStub(new NewMultiArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_MULTI_ARRAY)));
     }
 
     private void registerStub(Stub stub) {
@@ -453,11 +456,11 @@
         return "MARK:" + mark.id;
     }
 
-    private static void addExceptionHandlersComment(CompilationResult tm, HexCodeFile hcf) {
-        if (!tm.getExceptionHandlers().isEmpty()) {
+    private static void addExceptionHandlersComment(CompilationResult compResult, HexCodeFile hcf) {
+        if (!compResult.getExceptionHandlers().isEmpty()) {
             String nl = HexCodeFile.NEW_LINE;
             StringBuilder buf = new StringBuilder("------ Exception Handlers ------").append(nl);
-            for (CompilationResult.ExceptionHandler e : tm.getExceptionHandlers()) {
+            for (CompilationResult.ExceptionHandler e : compResult.getExceptionHandlers()) {
                 buf.append("    ").append(e.pcOffset).append(" -> ").append(e.handlerPos).append(nl);
                 hcf.addComment(e.pcOffset, "[exception -> " + e.handlerPos + "]");
                 hcf.addComment(e.handlerPos, "[exception handler for " + e.pcOffset + "]");
@@ -516,7 +519,7 @@
             ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n;
             ValueNode array = arrayLengthNode.array();
             ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(LocationNode.FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt()));
-            arrayLengthRead.dependencies().add(tool.createNullCheckGuard(array));
+            tool.createNullCheckGuard(arrayLengthRead.dependencies(), array);
             graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
         } else if (n instanceof Invoke) {
             Invoke invoke = (Invoke) n;
@@ -525,7 +528,7 @@
                 NodeInputList<ValueNode> parameters = callTarget.arguments();
                 ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
                 if (!callTarget.isStatic() && receiver.kind() == Kind.Object && !receiver.objectStamp().nonNull()) {
-                    invoke.asNode().dependencies().add(tool.createNullCheckGuard(receiver));
+                    tool.createNullCheckGuard(invoke.asNode().dependencies(), receiver);
                 }
                 JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
 
@@ -536,13 +539,12 @@
                     if (!hsMethod.getDeclaringClass().isInterface()) {
                         int vtableEntryOffset = hsMethod.vtableEntryOffset();
                         if (vtableEntryOffset > 0) {
-                            // We use LocationNode.ANY_LOCATION for the reads that access the vtable
-                            // entry and the compiled code entry
-                            // as HotSpot does not guarantee they are final values.
                             assert vtableEntryOffset > 0;
-                            LoadHubNode hub = graph.add(new LoadHubNode(receiver, wordKind));
-                            ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph),
-                                            StampFactory.forKind(wordKind())));
+                            ReadNode hub = this.createReadHub(tool, graph, wordKind, receiver);
+                            ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod);
+                            // We use LocationNode.ANY_LOCATION for the reads that access the
+                            // compiled code entry as HotSpot does not guarantee they are final
+                            // values.
                             ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph),
                                             StampFactory.forKind(wordKind())));
 
@@ -568,7 +570,7 @@
             ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : loadField.object();
             assert loadField.kind() != Kind.Illegal;
             ReadNode memoryRead = graph.add(new ReadNode(object, ConstantLocationNode.create(field, field.getKind(), field.offset(), graph), loadField.stamp()));
-            memoryRead.dependencies().add(tool.createNullCheckGuard(object));
+            tool.createNullCheckGuard(memoryRead.dependencies(), object);
 
             graph.replaceFixedWithFixed(loadField, memoryRead);
 
@@ -585,7 +587,7 @@
             LocationNode location = ConstantLocationNode.create(field, field.getKind(), field.offset(), graph);
             WriteBarrierType barrierType = getFieldStoreBarrierType(storeField);
             WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), location, barrierType));
-            memoryWrite.dependencies().add(tool.createNullCheckGuard(object));
+            tool.createNullCheckGuard(memoryWrite.dependencies(), object);
             memoryWrite.setStateAfter(storeField.stateAfter());
             graph.replaceFixedWithFixed(storeField, memoryWrite);
             FixedWithNextNode last = memoryWrite;
@@ -661,17 +663,17 @@
             WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType));
             write.setStateAfter(store.stateAfter());
             graph.replaceFixedWithFixed(store, write);
-
         } else if (n instanceof LoadHubNode) {
             LoadHubNode loadHub = (LoadHubNode) n;
             assert loadHub.kind() == wordKind;
-            LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph);
             ValueNode object = loadHub.object();
-            assert !object.isConstant() || object.asConstant().isNull();
-            ValueNode guard = tool.createNullCheckGuard(object);
-            ReadNode hub = graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind())));
-            hub.dependencies().add(guard);
+            ReadNode hub = createReadHub(tool, graph, wordKind, object);
             graph.replaceFixed(loadHub, hub);
+        } else if (n instanceof LoadMethodNode) {
+            LoadMethodNode loadMethodNode = (LoadMethodNode) n;
+            ResolvedJavaMethod method = loadMethodNode.getMethod();
+            ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, loadMethodNode.getHub(), method);
+            graph.replaceFixed(loadMethodNode, metaspaceMethod);
         } else if (n instanceof FixedGuardNode) {
             FixedGuardNode node = (FixedGuardNode) n;
             ValueAnchorNode newAnchor = graph.add(new ValueAnchorNode(tool.createGuard(node.condition(), node.getReason(), node.getAction(), node.isNegated())));
@@ -721,6 +723,26 @@
         }
     }
 
+    private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, ResolvedJavaMethod method) {
+        HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
+        assert !hsMethod.getDeclaringClass().isInterface();
+
+        int vtableEntryOffset = hsMethod.vtableEntryOffset();
+        assert vtableEntryOffset > 0;
+        // We use LocationNode.ANY_LOCATION for the reads that access the vtable
+        // entry as HotSpot does not guarantee that this is a final value.
+        ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind())));
+        return metaspaceMethod;
+    }
+
+    private ReadNode createReadHub(LoweringTool tool, StructuredGraph graph, Kind wordKind, ValueNode object) {
+        LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph);
+        assert !object.isConstant() || object.asConstant().isNull();
+        ReadNode hub = graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind())));
+        tool.createNullCheckGuard(hub.dependencies(), object);
+        return hub;
+    }
+
     private static WriteBarrierType getFieldStoreBarrierType(StoreFieldNode storeField) {
         WriteBarrierType barrierType = WriteBarrierType.NONE;
         if (storeField.field().getKind() == Kind.Object && !storeField.value().objectStamp().alwaysNull()) {
@@ -951,8 +973,8 @@
 
     public String disassemble(InstalledCode code) {
         if (code.isValid()) {
-            long nmethod = ((HotSpotInstalledCode) code).getMethodAddress();
-            return graalRuntime.getCompilerToVM().disassembleNMethod(nmethod);
+            long codeBlob = ((HotSpotInstalledCode) code).getCodeBlob();
+            return graalRuntime.getCompilerToVM().disassembleCodeBlob(codeBlob);
         }
         return null;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.meta;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -118,7 +120,7 @@
         }
         JavaType type = argumentTypes[index];
         if (type == null || !(type instanceof ResolvedJavaType)) {
-            type = HotSpotGraalRuntime.getInstance().lookupType(arguments.get(index), (HotSpotResolvedObjectType) accessingClass, false);
+            type = graalRuntime().lookupType(arguments.get(index), (HotSpotResolvedObjectType) accessingClass, false);
             argumentTypes[index] = type;
         }
         return type;
@@ -137,7 +139,7 @@
     @Override
     public JavaType getReturnType(ResolvedJavaType accessingClass) {
         if (returnTypeCache == null || !(returnTypeCache instanceof ResolvedJavaType)) {
-            returnTypeCache = HotSpotGraalRuntime.getInstance().lookupType(returnType, (HotSpotResolvedObjectType) accessingClass, false);
+            returnTypeCache = graalRuntime().lookupType(returnType, (HotSpotResolvedObjectType) accessingClass, false);
         }
         return returnTypeCache;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.hotspot.meta;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.hotspot.*;
 
 /**
  * Implementation of {@link JavaType} for unresolved HotSpot classes.
@@ -85,6 +86,6 @@
 
     @Override
     public ResolvedJavaType resolve(ResolvedJavaType accessingClass) {
-        return (ResolvedJavaType) HotSpotGraalRuntime.getInstance().lookupType(getName(), (HotSpotResolvedObjectType) accessingClass, true);
+        return (ResolvedJavaType) graalRuntime().lookupType(getName(), (HotSpotResolvedObjectType) accessingClass, true);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -73,7 +73,7 @@
         HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen;
         StackSlot slot = hsGen.getLockSlot(lockDepth);
         if (!eliminated) {
-            Value result = gen.emitLea(slot);
+            Value result = gen.emitAddress(slot);
             gen.setResult(this, result);
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CRuntimeCall.java	Sun Apr 28 22:52:12 2013 +0200
@@ -0,0 +1,72 @@
+/*
+ * 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.nodes;
+
+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.lir.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Implements a direct call to a C/C++ HotSpot function.
+ */
+public class CRuntimeCall extends DeoptimizingFixedWithNextNode implements LIRGenLowerable {
+
+    @Input protected final NodeInputList<ValueNode> arguments;
+
+    private final Descriptor descriptor;
+
+    public CRuntimeCall(Descriptor descriptor, ValueNode... arguments) {
+        super(StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())));
+        this.arguments = new NodeInputList<>(this, arguments);
+        this.descriptor = descriptor;
+    }
+
+    @Override
+    public void generate(LIRGenerator gen) {
+        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(descriptor);
+        Value[] args = new Value[arguments.size()];
+        for (int i = 0; i < args.length; i++) {
+            args[i] = gen.operand(arguments.get(i));
+        }
+        Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, args);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @Override
+    public DeoptimizationReason getDeoptimizationReason() {
+        return null;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -26,7 +26,6 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -43,7 +42,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        Register rawThread = HotSpotGraalRuntime.getInstance().getRuntime().threadRegister();
+        Register rawThread = graalRuntime().getRuntime().threadRegister();
         gen.setResult(this, rawThread.asValue(this.kind()));
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -57,7 +57,7 @@
         HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen;
         StackSlot slot = hsGen.getLockSlot(lockDepth);
         // The register allocator cannot handle stack -> register moves so we use an LEA here
-        Value result = gen.emitMove(gen.emitLea(slot));
+        Value result = gen.emitMove(gen.emitAddress(slot));
         gen.setResult(this, result);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2009, 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.nodes;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Removes the current frame and tail calls the uncommon trap routine.
+ */
+@NodeInfo(shortName = "DeoptCaller", nameTemplate = "DeoptCaller {p#reason/s}")
+public class DeoptimizeCallerNode extends ControlSinkNode implements LIRLowerable {
+
+    private final DeoptimizationAction action;
+    private final DeoptimizationReason reason;
+
+    public DeoptimizeCallerNode(DeoptimizationAction action, DeoptimizationReason reason) {
+        super(StampFactory.forVoid());
+        this.action = action;
+        this.reason = reason;
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool gen) {
+        ((HotSpotLIRGenerator) gen).emitDeoptimizeCaller(action, reason);
+    }
+
+    @NodeIntrinsic
+    public static native void deopt(@ConstantNodeParameter DeoptimizationAction action, @ConstantNodeParameter DeoptimizationReason reason);
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -47,7 +47,7 @@
     public void generate(LIRGenerator gen) {
         int size = rank * 4;
         StackSlot array = gen.frameMap().allocateStackBlock(size, false);
-        Value result = gen.emitLea(array);
+        Value result = gen.emitAddress(array);
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -46,7 +46,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        Value obj = gen.newVariable(gen.target().wordKind);
+        AllocatableValue obj = gen.newVariable(gen.target().wordKind);
         gen.emitMove(obj, gen.operand(object));
         gen.setResult(this, obj);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,9 +22,10 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodes.*;
@@ -68,11 +69,11 @@
         ResolvedJavaMethod method = null;
         ResolvedJavaField methodField = null;
         ResolvedJavaField metaspaceMethodField = null;
-        ResolvedJavaField nmethodField = null;
+        ResolvedJavaField codeBlobField = null;
         try {
             method = tool.lookupJavaMethod(HotSpotInstalledCodeExecuteNode.class.getMethod("placeholder", Object.class, Object.class, Object.class));
             methodField = tool.lookupJavaField(HotSpotInstalledCode.class.getDeclaredField("method"));
-            nmethodField = tool.lookupJavaField(HotSpotInstalledCode.class.getDeclaredField("nmethod"));
+            codeBlobField = tool.lookupJavaField(HotSpotInstalledCode.class.getDeclaredField("codeBlob"));
             metaspaceMethodField = tool.lookupJavaField(HotSpotResolvedJavaMethod.class.getDeclaredField("metaspaceMethod"));
         } catch (NoSuchMethodException | SecurityException | NoSuchFieldException e) {
             throw new IllegalStateException(e);
@@ -85,8 +86,8 @@
 
         StructuredGraph g = (StructuredGraph) graph();
 
-        LoadFieldNode loadnmethod = g.add(new LoadFieldNode(code, nmethodField));
-        UnsafeLoadNode load = g.add(new UnsafeLoadNode(loadnmethod, verifiedEntryPointOffset, ConstantNode.forLong(0, graph()), HotSpotGraalRuntime.getInstance().getTarget().wordKind));
+        LoadFieldNode loadCodeBlob = g.add(new LoadFieldNode(code, codeBlobField));
+        UnsafeLoadNode load = g.add(new UnsafeLoadNode(loadCodeBlob, verifiedEntryPointOffset, ConstantNode.forLong(0, graph()), graalRuntime().getTarget().wordKind));
 
         LoadFieldNode loadMethod = g.add(new LoadFieldNode(code, methodField));
         LoadFieldNode loadmetaspaceMethod = g.add(new LoadFieldNode(loadMethod, metaspaceMethodField));
@@ -101,7 +102,7 @@
         g.addBeforeFixed(invoke, loadmetaspaceMethod);
         g.addBeforeFixed(loadmetaspaceMethod, loadMethod);
         g.addBeforeFixed(invoke, load);
-        g.addBeforeFixed(load, loadnmethod);
+        g.addBeforeFixed(load, loadCodeBlob);
 
         return invoke;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -43,7 +43,7 @@
     public void generate(LIRGenerator gen) {
         assert graph().getNodes().filter(MonitorCounterNode.class).count() == 1 : "monitor counters not canonicalized to single instance";
         StackSlot counter = gen.frameMap().allocateStackBlock(gen.target().wordSize, false);
-        Value result = gen.emitLea(counter);
+        Value result = gen.emitAddress(counter);
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java	Sun Apr 28 22:52:12 2013 +0200
@@ -60,7 +60,7 @@
         HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen;
         StackSlot slot = hsGen.getLockSlot(lockDepth);
         RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(MonitorExitStubCall.MONITOREXIT);
-        gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(object), gen.emitLea(slot));
+        gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(object), gen.emitAddress(slot));
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArraySlowStubCall.java	Sun Apr 28 22:34:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +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.nodes;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.word.*;
-
-/**
- * Node implementing a call to the {@code new_array} stub.
- */
-public class NewArraySlowStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
-
-    private static final Stamp defaultStamp = StampFactory.objectNonNull();
-
-    @Input private final ValueNode hub;
-    @Input private final ValueNode length;
-
-    public static final Descriptor NEW_ARRAY_SLOW = new Descriptor("new_array_slow", false, Object.class, Word.class, int.class);
-
-    public NewArraySlowStubCall(ValueNode hub, ValueNode length) {
-        super(defaultStamp);
-        this.hub = hub;
-        this.length = length;
-    }
-
-    @Override
-    public boolean inferStamp() {
-        if (stamp() == defaultStamp && hub.isConstant()) {
-            updateStamp(StampFactory.exactNonNull(HotSpotResolvedObjectType.fromMetaspaceKlass(hub.asConstant())));
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_ARRAY_SLOW);
-        Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub), gen.operand(length));
-        gen.setResult(this, result);
-    }
-
-    @NodeIntrinsic
-    public static native Object call(Word hub, int length);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceSlowStubCall.java	Sun Apr 28 22:34:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +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.nodes;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.word.*;
-
-/**
- * Node implementing a call to HotSpot's {@code new_instance} stub.
- */
-public class NewInstanceSlowStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
-
-    private static final Stamp defaultStamp = StampFactory.objectNonNull();
-
-    @Input private final ValueNode hub;
-
-    public static final Descriptor NEW_INSTANCE_SLOW = new Descriptor("new_instance_slow", false, Object.class, Word.class);
-
-    public NewInstanceSlowStubCall(ValueNode hub) {
-        super(defaultStamp);
-        this.hub = hub;
-    }
-
-    @Override
-    public boolean inferStamp() {
-        if (stamp() == defaultStamp && hub.isConstant()) {
-            updateStamp(StampFactory.exactNonNull(HotSpotResolvedObjectType.fromMetaspaceKlass(hub.asConstant())));
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_INSTANCE_SLOW);
-        Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub));
-        gen.setResult(this, result);
-    }
-
-    @NodeIntrinsic
-    public static native Object call(Word hub);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Sun Apr 28 22:52:12 2013 +0200
@@ -28,13 +28,14 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
- * Node implementing a call to HotSpot's {@code new_multi_array} stub.
+ * Node implementing a call to {@link NewMultiArrayStub}.
  */
 public class NewMultiArrayStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
 import java.lang.reflect.*;
 import java.util.*;
 
@@ -58,7 +60,7 @@
     @Override
     public void generate(LIRGeneratorTool generator) {
         LIRGenerator gen = (LIRGenerator) generator;
-        HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig();
+        HotSpotVMConfig config = graalRuntime().getConfig();
         ResolvedJavaMethod method = frameState.method();
         boolean isStatic = Modifier.isStatic(method.getModifiers());
 
@@ -69,7 +71,8 @@
             parameters.add(frameState.localAt(slot));
         }
         Value[] args = gen.visitInvokeArguments(cc, parameters);
-        Value entry = gen.emitLoad(Kind.Long, gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0, null);
+        Value address = gen.emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0);
+        Value entry = gen.emitLoad(Kind.Long, address, null);
         HotSpotLIRGenerator hsgen = (HotSpotLIRGenerator) gen;
         hsgen.emitTailcall(args, entry);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java	Sun Apr 28 22:52:12 2013 +0200
@@ -84,8 +84,8 @@
         long nonVectorBytes = byteLength % VECTOR_SIZE;
         long srcOffset = (long) srcPos * elementSize;
         long destOffset = (long) destPos * elementSize;
-        if (src == dest && srcPos < destPos) { // bad aliased case
-            probability(NOT_FREQUENT_PROBABILITY);
+        if (probability(NOT_FREQUENT_PROBABILITY, src == dest) && probability(NOT_FREQUENT_PROBABILITY, srcPos < destPos)) {
+            // bad aliased case
             for (long i = byteLength - elementSize; i >= byteLength - nonVectorBytes; i -= elementSize) {
                 UnsafeStoreNode.store(dest, header, i + destOffset, UnsafeLoadNode.load(src, header, i + srcOffset, baseKind), baseKind);
             }
@@ -107,7 +107,6 @@
 
     public static void checkNonNull(Object obj) {
         if (obj == null) {
-            probability(DEOPT_PATH_PROBABILITY);
             checkNPECounter.inc();
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
@@ -116,7 +115,6 @@
     public static int checkArrayType(Word hub) {
         int layoutHelper = readLayoutHelper(hub);
         if (layoutHelper >= 0) {
-            probability(DEOPT_PATH_PROBABILITY);
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
         return layoutHelper;
@@ -124,27 +122,22 @@
 
     public static void checkLimits(Object src, int srcPos, Object dest, int destPos, int length) {
         if (srcPos < 0) {
-            probability(DEOPT_PATH_PROBABILITY);
             checkAIOOBECounter.inc();
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
         if (destPos < 0) {
-            probability(DEOPT_PATH_PROBABILITY);
             checkAIOOBECounter.inc();
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
         if (length < 0) {
-            probability(DEOPT_PATH_PROBABILITY);
             checkAIOOBECounter.inc();
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
         if (srcPos + length > ArrayLengthNode.arrayLength(src)) {
-            probability(DEOPT_PATH_PROBABILITY);
             checkAIOOBECounter.inc();
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
         if (destPos + length > ArrayLengthNode.arrayLength(dest)) {
-            probability(DEOPT_PATH_PROBABILITY);
             checkAIOOBECounter.inc();
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
@@ -278,13 +271,10 @@
         int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
         final boolean isObjectArray = ((layoutHelper & layoutHelperElementTypePrimitiveInPlace()) == 0);
 
-        if (srcHub.equal(destHub) && src != dest) {
-            probability(FAST_PATH_PROBABILITY);
-
+        if (probability(FAST_PATH_PROBABILITY, srcHub.equal(destHub)) && probability(FAST_PATH_PROBABILITY, src != dest)) {
             checkLimits(src, srcPos, dest, destPos, length);
-            if (isObjectArray) {
+            if (probability(FAST_PATH_PROBABILITY, isObjectArray)) {
                 genericObjectExactCallCounter.inc();
-                probability(FAST_PATH_PROBABILITY);
                 arrayObjectCopy(src, srcPos, dest, destPos, length);
             } else {
                 genericPrimitiveCallCounter.inc();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java	Sun Apr 28 22:52:12 2013 +0200
@@ -65,13 +65,11 @@
      */
     @Snippet
     public static Object checkcastExact(Object object, Word exactHub, @ConstantParameter boolean checkNull) {
-        if (checkNull && object == null) {
-            probability(NOT_FREQUENT_PROBABILITY);
+        if (checkNull && probability(NOT_FREQUENT_PROBABILITY, object == null)) {
             isNull.inc();
         } else {
             Word objectHub = loadHub(object);
             if (objectHub.notEqual(exactHub)) {
-                probability(DEOPT_PATH_PROBABILITY);
                 exactMiss.inc();
                 DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException);
             }
@@ -92,13 +90,11 @@
      */
     @Snippet
     public static Object checkcastPrimary(Word hub, Object object, @ConstantParameter int superCheckOffset, @ConstantParameter boolean checkNull) {
-        if (checkNull && object == null) {
-            probability(NOT_FREQUENT_PROBABILITY);
+        if (checkNull && probability(NOT_FREQUENT_PROBABILITY, object == null)) {
             isNull.inc();
         } else {
             Word objectHub = loadHub(object);
             if (objectHub.readWord(superCheckOffset, FINAL_LOCATION).notEqual(hub)) {
-                probability(DEOPT_PATH_PROBABILITY);
                 displayMiss.inc();
                 DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException);
             }
@@ -113,8 +109,7 @@
      */
     @Snippet
     public static Object checkcastSecondary(Word hub, Object object, @VarargsParameter Word[] hints, @ConstantParameter boolean checkNull) {
-        if (checkNull && object == null) {
-            probability(NOT_FREQUENT_PROBABILITY);
+        if (checkNull && probability(NOT_FREQUENT_PROBABILITY, object == null)) {
             isNull.inc();
         } else {
             Word objectHub = loadHub(object);
@@ -142,8 +137,7 @@
      */
     @Snippet
     public static Object checkcastDynamic(Word hub, Object object, @ConstantParameter boolean checkNull) {
-        if (checkNull && object == null) {
-            probability(NOT_FREQUENT_PROBABILITY);
+        if (checkNull && probability(NOT_FREQUENT_PROBABILITY, object == null)) {
             isNull.inc();
         } else {
             Word objectHub = loadHub(object);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java	Sun Apr 28 22:52:12 2013 +0200
@@ -49,7 +49,7 @@
     public static final Object FINAL_LOCATION = LocationNode.FINAL_LOCATION;
 
     public static HotSpotVMConfig config() {
-        return HotSpotGraalRuntime.getInstance().getConfig();
+        return graalRuntime().getConfig();
     }
 
     @Fold
@@ -97,6 +97,20 @@
         return config().threadTlabStartOffset;
     }
 
+    public static final Object PENDING_EXCEPTION_LOCATION = LocationNode.createLocation("PendingException");
+
+    @Fold
+    private static int threadPendingExceptionOffset() {
+        return config().pendingExceptionOffset;
+    }
+
+    public static final Object OBJECT_RESULT_LOCATION = LocationNode.createLocation("ObjectResult");
+
+    @Fold
+    private static int objectResultOffset() {
+        return config().threadObjectResultOffset;
+    }
+
     public static Object readExceptionOop(Word thread) {
         return thread.readObject(threadExceptionOopOffset(), EXCEPTION_OOP_LOCATION);
     }
@@ -131,6 +145,28 @@
         thread.writeWord(threadTlabEndOffset(), end, TLAB_END_LOCATION);
     }
 
+    /**
+     * Clears the pending exception if for the given thread.
+     * 
+     * @return {@code true} if there was a pending exception
+     */
+    public static boolean clearPendingException(Word thread) {
+        boolean result = thread.readObject(threadPendingExceptionOffset(), PENDING_EXCEPTION_LOCATION) != null;
+        thread.writeObject(threadPendingExceptionOffset(), null);
+        return result;
+    }
+
+    /**
+     * Gets and clears the object result from a runtime call stored in a thread local.
+     * 
+     * @return the object that was in the thread local
+     */
+    public static Object getAndClearObjectResult(Word thread) {
+        Object result = thread.readObject(objectResultOffset(), OBJECT_RESULT_LOCATION);
+        thread.writeObject(objectResultOffset(), null);
+        return result;
+    }
+
     @Fold
     public static int threadObjectOffset() {
         return config().threadObjectOffset;
@@ -148,22 +184,22 @@
 
     @Fold
     public static Kind wordKind() {
-        return HotSpotGraalRuntime.getInstance().getTarget().wordKind;
+        return graalRuntime().getTarget().wordKind;
     }
 
     @Fold
     public static Register threadRegister() {
-        return HotSpotGraalRuntime.getInstance().getRuntime().threadRegister();
+        return graalRuntime().getRuntime().threadRegister();
     }
 
     @Fold
     public static Register stackPointerRegister() {
-        return HotSpotGraalRuntime.getInstance().getRuntime().stackPointerRegister();
+        return graalRuntime().getRuntime().stackPointerRegister();
     }
 
     @Fold
     public static int wordSize() {
-        return HotSpotGraalRuntime.getInstance().getTarget().wordSize;
+        return graalRuntime().getTarget().wordSize;
     }
 
     @Fold
@@ -608,11 +644,9 @@
 
         // this code is independent from biased locking (although it does not look that way)
         final Word biasedLock = mark.and(biasedLockMaskInPlace());
-        if (biasedLock.equal(Word.unsigned(unlockedMask()))) {
-            probability(FAST_PATH_PROBABILITY);
+        if (probability(FAST_PATH_PROBABILITY, biasedLock.equal(Word.unsigned(unlockedMask())))) {
             int hash = (int) mark.unsignedShiftRight(identityHashCodeShift()).rawValue();
-            if (hash != uninitializedIdentityHashCodeValue()) {
-                probability(FAST_PATH_PROBABILITY);
+            if (probability(FAST_PATH_PROBABILITY, hash != uninitializedIdentityHashCodeValue())) {
                 return hash;
             }
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Sun Apr 28 22:52:12 2013 +0200
@@ -58,14 +58,12 @@
      */
     @Snippet
     public static Object instanceofExact(Object object, Word exactHub, Object trueValue, Object falseValue, @ConstantParameter boolean checkNull) {
-        if (checkNull && object == null) {
-            probability(NOT_FREQUENT_PROBABILITY);
+        if (checkNull && probability(NOT_FREQUENT_PROBABILITY, object == null)) {
             isNull.inc();
             return falseValue;
         }
         Word objectHub = loadHub(object);
-        if (objectHub.notEqual(exactHub)) {
-            probability(LIKELY_PROBABILITY);
+        if (probability(LIKELY_PROBABILITY, objectHub.notEqual(exactHub))) {
             exactMiss.inc();
             return falseValue;
         }
@@ -78,14 +76,12 @@
      */
     @Snippet
     public static Object instanceofPrimary(Word hub, Object object, @ConstantParameter int superCheckOffset, Object trueValue, Object falseValue, @ConstantParameter boolean checkNull) {
-        if (checkNull && object == null) {
-            probability(NOT_FREQUENT_PROBABILITY);
+        if (checkNull && probability(NOT_FREQUENT_PROBABILITY, object == null)) {
             isNull.inc();
             return falseValue;
         }
         Word objectHub = loadHub(object);
-        if (objectHub.readWord(superCheckOffset, FINAL_LOCATION).notEqual(hub)) {
-            probability(NOT_LIKELY_PROBABILITY);
+        if (probability(NOT_LIKELY_PROBABILITY, objectHub.readWord(superCheckOffset, FINAL_LOCATION).notEqual(hub))) {
             displayMiss.inc();
             return falseValue;
         }
@@ -99,8 +95,7 @@
     @Snippet
     public static Object instanceofSecondary(Word hub, Object object, @VarargsParameter Word[] hints, @VarargsParameter boolean[] hintIsPositive, Object trueValue, Object falseValue,
                     @ConstantParameter boolean checkNull) {
-        if (checkNull && object == null) {
-            probability(NOT_FREQUENT_PROBABILITY);
+        if (checkNull && probability(NOT_FREQUENT_PROBABILITY, object == null)) {
             isNull.inc();
             return falseValue;
         }
@@ -110,8 +105,7 @@
         for (int i = 0; i < hints.length; i++) {
             Word hintHub = hints[i];
             boolean positive = hintIsPositive[i];
-            if (hintHub.equal(objectHub)) {
-                probability(NOT_FREQUENT_PROBABILITY);
+            if (probability(NOT_FREQUENT_PROBABILITY, hintHub.equal(objectHub))) {
                 hintsHit.inc();
                 return positive ? trueValue : falseValue;
             }
@@ -127,8 +121,7 @@
      */
     @Snippet
     public static Object instanceofDynamic(Class mirror, Object object, Object trueValue, Object falseValue, @ConstantParameter boolean checkNull) {
-        if (checkNull && object == null) {
-            probability(NOT_FREQUENT_PROBABILITY);
+        if (checkNull && probability(NOT_FREQUENT_PROBABILITY, object == null)) {
             isNull.inc();
             return falseValue;
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Sun Apr 28 22:52:12 2013 +0200
@@ -102,10 +102,9 @@
             final Word biasableLockBits = mark.and(biasedLockMaskInPlace());
 
             // First check to see whether biasing is enabled for this object
-            if (biasableLockBits.notEqual(Word.unsigned(biasedLockPattern()))) {
+            if (probability(NOT_FREQUENT_PROBABILITY, biasableLockBits.notEqual(Word.unsigned(biasedLockPattern())))) {
                 // Biasing not enabled -> fall through to lightweight locking
             } else {
-                probability(FREQUENT_PROBABILITY);
                 // The bias pattern is present in the object's mark word. Need to check
                 // whether the bias owner and the epoch are both still current.
                 Word hub = loadHub(object);
@@ -115,9 +114,8 @@
                 trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord);
                 trace(trace, "           thread: 0x%016lx\n", thread);
                 trace(trace, "              tmp: 0x%016lx\n", tmp);
-                if (tmp.equal(0)) {
+                if (probability(FREQUENT_PROBABILITY, tmp.equal(0))) {
                     // Object is already biased to current thread -> done
-                    probability(FREQUENT_PROBABILITY);
                     traceObject(trace, "+lock{bias:existing}", object);
                     return;
                 }
@@ -131,8 +129,7 @@
                 // If the low three bits in the xor result aren't clear, that means
                 // the prototype header is no longer biasable and we have to revoke
                 // the bias on this object.
-                if (tmp.and(biasedLockMaskInPlace()).equal(0)) {
-                    probability(FREQUENT_PROBABILITY);
+                if (probability(FREQUENT_PROBABILITY, tmp.and(biasedLockMaskInPlace()).equal(0))) {
                     // Biasing is still enabled for object's type. See whether the
                     // epoch of the current bias is still valid, meaning that the epoch
                     // bits of the mark word are equal to the epoch bits of the
@@ -142,8 +139,7 @@
                     // that the current epoch is invalid in order to do this because
                     // otherwise the manipulations it performs on the mark word are
                     // illegal.
-                    if (tmp.and(epochMaskInPlace()).equal(0)) {
-                        probability(FREQUENT_PROBABILITY);
+                    if (probability(FREQUENT_PROBABILITY, tmp.and(epochMaskInPlace()).equal(0))) {
                         // The epoch of the current bias is still valid but we know nothing
                         // about the owner; it might be set or it might be clear. Try to
                         // acquire the bias of the object using an atomic operation. If this
@@ -154,7 +150,7 @@
                         Word biasedMark = unbiasedMark.or(thread);
                         trace(trace, "     unbiasedMark: 0x%016lx\n", unbiasedMark);
                         trace(trace, "       biasedMark: 0x%016lx\n", biasedMark);
-                        if (compareAndSwap(object, markOffset(), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark)) {
+                        if (probability(VERY_FAST_DEOPT_PATH_PROBABILITY, compareAndSwap(object, markOffset(), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark))) {
                             // Object is now biased to current thread -> done
                             traceObject(trace, "+lock{bias:acquired}", object);
                             return;
@@ -162,7 +158,6 @@
                         // If the biasing toward our thread failed, this means that another thread
                         // owns the bias and we need to revoke that bias. The revocation will occur
                         // in the interpreter runtime.
-                        probability(DEOPT_PATH_PROBABILITY);
                         traceObject(trace, "+lock{stub:revoke}", object);
                         MonitorEnterStubCall.call(object, lock);
                         return;
@@ -175,7 +170,7 @@
                         // the bias from one thread to another directly in this situation.
                         Word biasedMark = prototypeMarkWord.or(thread);
                         trace(trace, "       biasedMark: 0x%016lx\n", biasedMark);
-                        if (compareAndSwap(object, markOffset(), mark, biasedMark, MARK_WORD_LOCATION).equal(mark)) {
+                        if (probability(VERY_FAST_DEOPT_PATH_PROBABILITY, compareAndSwap(object, markOffset(), mark, biasedMark, MARK_WORD_LOCATION).equal(mark))) {
                             // Object is now biased to current thread -> done
                             traceObject(trace, "+lock{bias:transfer}", object);
                             return;
@@ -183,7 +178,6 @@
                         // If the biasing toward our thread failed, then another thread
                         // succeeded in biasing it toward itself and we need to revoke that
                         // bias. The revocation will occur in the runtime in the slow case.
-                        probability(DEOPT_PATH_PROBABILITY);
                         traceObject(trace, "+lock{stub:epoch-expired}", object);
                         MonitorEnterStubCall.call(object, lock);
                         return;
@@ -239,9 +233,8 @@
             // significant 2 bits cleared and page_size is a power of 2
             final Word alignedMask = Word.unsigned(wordSize() - 1);
             final Word stackPointer = stackPointer();
-            if (currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).notEqual(0)) {
+            if (probability(VERY_SLOW_PATH_PROBABILITY, currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).notEqual(0))) {
                 // Most likely not a recursive lock, go into a slow runtime call
-                probability(DEOPT_PATH_PROBABILITY);
                 traceObject(trace, "+lock{stub:failed-cas}", object);
                 MonitorEnterStubCall.call(object, lock);
                 return;
@@ -290,8 +283,7 @@
             // the bias bit would be clear.
             final Word mark = loadWordFromObject(object, markOffset());
             trace(trace, "             mark: 0x%016lx\n", mark);
-            if (mark.and(biasedLockMaskInPlace()).equal(Word.unsigned(biasedLockPattern()))) {
-                probability(FREQUENT_PROBABILITY);
+            if (probability(FREQUENT_PROBABILITY, mark.and(biasedLockMaskInPlace()).equal(Word.unsigned(biasedLockPattern())))) {
                 endLockScope();
                 decCounter();
                 traceObject(trace, "-lock{bias}", object);
@@ -313,10 +305,9 @@
             // Test if object's mark word is pointing to the displaced mark word, and if so, restore
             // the displaced mark in the object - if the object's mark word is not pointing to
             // the displaced mark word, do unlocking via runtime call.
-            if (DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark, MARK_WORD_LOCATION).notEqual(lock)) {
+            if (probability(VERY_SLOW_PATH_PROBABILITY, DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark, MARK_WORD_LOCATION).notEqual(lock))) {
                 // The object's mark word was not pointing to the displaced header,
                 // we do unlocking via runtime call.
-                probability(DEOPT_PATH_PROBABILITY);
                 traceObject(trace, "-lock{stub}", object);
                 MonitorExitStubCall.call(object);
             } else {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Sun Apr 28 22:52:12 2013 +0200
@@ -64,8 +64,7 @@
          * 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(FAST_PATH_PROBABILITY);
+        if (probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
             writeTlabTop(thread, newTop);
             return top;
         }
@@ -76,11 +75,10 @@
     public static Object initializeObject(Word memory, Word hub, Word prototypeMarkWord, @ConstantParameter int size, @ConstantParameter boolean fillContents, @ConstantParameter boolean locked) {
 
         Object result;
-        if (memory.equal(0)) {
+        if (probability(SLOW_PATH_PROBABILITY, memory.equal(0))) {
             new_stub.inc();
             result = NewInstanceStubCall.call(hub);
         } else {
-            probability(FAST_PATH_PROBABILITY);
             if (locked) {
                 formatObject(hub, size, memory, thread().or(biasedLockPattern()), fillContents);
             } else {
@@ -108,11 +106,10 @@
 
     private static Object initializeArray(Word memory, Word hub, int length, int allocationSize, Word prototypeMarkWord, int headerSize, boolean fillContents) {
         Object result;
-        if (memory.equal(0)) {
+        if (probability(SLOW_PATH_PROBABILITY, memory.equal(0))) {
             newarray_stub.inc();
             result = NewArrayStubCall.call(hub, length);
         } else {
-            probability(FAST_PATH_PROBABILITY);
             newarray_loopInit.inc();
             formatArray(hub, allocationSize, length, headerSize, memory, prototypeMarkWord, fillContents);
             result = memory.toObject();
@@ -130,7 +127,6 @@
     public static Object allocateArrayAndInitialize(int length, @ConstantParameter int alignment, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize,
                     @ConstantParameter boolean fillContents, @ConstantParameter ResolvedJavaType type) {
         if (!belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) {
-            probability(DEOPT_PATH_PROBABILITY);
             // This handles both negative array sizes and very large array sizes
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Sun Apr 28 22:52:12 2013 +0200
@@ -84,7 +84,6 @@
     private static Word getAndCheckHub(Object src) {
         Word hub = loadHub(src);
         if (!(src instanceof Cloneable)) {
-            probability(DEOPT_PATH_PROBABILITY);
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
         return hub;
@@ -110,8 +109,7 @@
         genericCloneCounter.inc();
         Word hub = getAndCheckHub(src);
         int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION);
-        if (layoutHelper < 0) {
-            probability(LIKELY_PROBABILITY);
+        if (probability(LIKELY_PROBABILITY, layoutHelper < 0)) {
             genericArrayCloneCounter.inc();
             return arrayClone(src, hub, layoutHelper);
         } else {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java	Sun Apr 28 22:52:12 2013 +0200
@@ -56,8 +56,7 @@
 
     @MethodSubstitution
     public static int identityHashCode(Object x) {
-        if (x == null) {
-            probability(NOT_FREQUENT_PROBABILITY);
+        if (probability(NOT_FREQUENT_PROBABILITY, x == null)) {
             return 0;
         }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java	Sun Apr 28 22:52:12 2013 +0200
@@ -37,6 +37,8 @@
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.word.*;
 
+//JaCoCo Exclude
+
 /**
  * Utilities and common code paths used by the type check snippets.
  */
@@ -89,8 +91,7 @@
         Word secondarySupers = s.readWord(secondarySupersOffset(), SECONDARY_SUPERS_LOCATION);
         int length = secondarySupers.readInt(metaspaceArrayLengthOffset(), FINAL_LOCATION);
         for (int i = 0; i < length; i++) {
-            if (t.equal(loadSecondarySupersElement(secondarySupers, i))) {
-                probability(NOT_LIKELY_PROBABILITY);
+            if (probability(NOT_LIKELY_PROBABILITY, t.equal(loadSecondarySupersElement(secondarySupers, i)))) {
                 s.writeWord(secondarySuperCacheOffset(), t, SECONDARY_SUPER_CACHE_LOCATION);
                 secondariesHit.inc();
                 return true;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,11 +22,17 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
+import static com.oracle.graal.api.code.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
 import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
 import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*;
 
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.Node.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
@@ -42,7 +48,7 @@
  * Stub implementing the fast path for TLAB refill during instance class allocation. This stub is
  * called from the {@linkplain NewObjectSnippets inline} allocation code when TLAB allocation fails.
  * If this stub fails to refill the TLAB or allocate the object, it calls out to the HotSpot C++
- * runtime for to complete the allocation.
+ * runtime to complete the allocation.
  */
 public class NewArrayStub extends Stub {
 
@@ -54,10 +60,16 @@
     protected Arguments makeArguments(SnippetInfo stub) {
         HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) runtime.lookupJavaType(int[].class);
 
+        // RuntimeStub cannot (currently) support oops or metadata embedded in the code so we
+        // convert the hub (i.e., Klass*) for int[] to be a naked word. This should be safe since
+        // the int[] class will never be unloaded.
+        Constant intArrayHub = intArrayType.klass();
+        intArrayHub = Constant.forIntegerKind(graalRuntime().getTarget().wordKind, intArrayHub.asLong(), null);
+
         Arguments args = new Arguments(stub);
         args.add("hub", null);
         args.add("length", null);
-        args.addConst("intArrayHub", intArrayType.klass());
+        args.addConst("intArrayHub", intArrayHub);
         args.addConst("log", Boolean.getBoolean("graal.logNewArrayStub"));
         return args;
     }
@@ -92,7 +104,20 @@
                 return verifyOop(memory.toObject());
             }
         }
-        log(log, "newArray: calling new_array_slow", 0L);
-        return verifyOop(NewArraySlowStubCall.call(hub, length));
+        log(log, "newArray: calling new_array_c\n", 0L);
+
+        newArrayC(NEW_ARRAY_C, thread(), hub, length);
+
+        if (clearPendingException(thread())) {
+            log(log, "newArray: deoptimizing to caller\n", 0L);
+            getAndClearObjectResult(thread());
+            DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+        }
+        return verifyOop(getAndClearObjectResult(thread()));
     }
+
+    public static final Descriptor NEW_ARRAY_C = new Descriptor("new_array_c", false, void.class, Word.class, Word.class, int.class);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void newArrayC(@ConstantNodeParameter Descriptor newArrayC, Word thread, Word hub, int length);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,12 +22,18 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
+import static com.oracle.graal.api.code.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
 import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
 
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
@@ -56,9 +62,15 @@
     protected Arguments makeArguments(SnippetInfo stub) {
         HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) runtime.lookupJavaType(int[].class);
 
+        // RuntimeStub cannot (currently) support oops or metadata embedded in the code so we
+        // convert the hub (i.e., Klass*) for int[] to be a naked word. This should be safe since
+        // the int[] class will never be unloaded.
+        Constant intArrayHub = intArrayType.klass();
+        intArrayHub = Constant.forIntegerKind(graalRuntime().getTarget().wordKind, intArrayHub.asLong(), null);
+
         Arguments args = new Arguments(stub);
         args.add("hub", null);
-        args.addConst("intArrayHub", intArrayType.klass());
+        args.addConst("intArrayHub", intArrayHub);
         args.addConst("log", Boolean.getBoolean("graal.logNewInstanceStub"));
         return args;
     }
@@ -86,7 +98,17 @@
                 }
             }
         }
-        return verifyOop(NewInstanceSlowStubCall.call(hub));
+
+        log(log, "newInstance: calling new_instance_c\n", 0L);
+
+        newInstanceC(NEW_INSTANCE_C, thread(), hub);
+
+        if (clearPendingException(thread())) {
+            log(log, "newInstance: deoptimizing to caller\n", 0L);
+            getAndClearObjectResult(thread());
+            DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+        }
+        return verifyOop(getAndClearObjectResult(thread()));
     }
 
     /**
@@ -208,4 +230,9 @@
     private static boolean forceSlowPath() {
         return Boolean.getBoolean("graal.newInstanceStub.forceSlowPath");
     }
+
+    public static final Descriptor NEW_INSTANCE_C = new Descriptor("new_instance_c", false, void.class, Word.class, Word.class);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void newInstanceC(@ConstantNodeParameter Descriptor newInstanceC, Word thread, Word hub);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewMultiArrayStub.java	Sun Apr 28 22:52:12 2013 +0200
@@ -0,0 +1,72 @@
+/*
+ * 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.stubs;
+
+import static com.oracle.graal.api.code.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.SnippetTemplate.Arguments;
+import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
+import com.oracle.graal.word.*;
+
+public class NewMultiArrayStub extends Stub {
+
+    public NewMultiArrayStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage, "newMultiArray");
+    }
+
+    @Override
+    protected Arguments makeArguments(SnippetInfo stub) {
+        Arguments args = new Arguments(stub);
+        args.add("hub", null);
+        args.add("rank", null);
+        args.add("dims", null);
+        return args;
+    }
+
+    @Snippet
+    private static Object newMultiArray(Word hub, int rank, Word dims) {
+        newMultiArrayC(NEW_MULTI_ARRAY_C, thread(), hub, rank, dims);
+
+        if (clearPendingException(thread())) {
+            getAndClearObjectResult(thread());
+            DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+        }
+        return verifyOop(getAndClearObjectResult(thread()));
+    }
+
+    public static final Descriptor NEW_MULTI_ARRAY_C = new Descriptor("new_multi_array_c", false, void.class, Word.class, Word.class, int.class, Word.class);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void newMultiArrayC(@ConstantNodeParameter Descriptor newArrayC, Word thread, Word hub, int rank, Word dims);
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Sun Apr 28 22:52:12 2013 +0200
@@ -28,6 +28,7 @@
 import java.util.concurrent.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CompilationResult.DataPatch;
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.*;
@@ -51,6 +52,8 @@
 import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
 import com.oracle.graal.word.*;
 
+//JaCoCo Exclude
+
 /**
  * Base class for implementing some low level code providing the out-of-line slow path for a
  * snippet. A concrete stub is defined a subclass of this class.
@@ -76,13 +79,13 @@
     protected InstalledCode code;
 
     /**
-     * The registers defined by this stub.
+     * The registers/temporaries defined by this stub.
      */
     private Set<Register> definedRegisters;
 
     public void initDefinedRegisters(Set<Register> registers) {
         assert registers != null;
-        assert definedRegisters == null : "cannot redefine";
+        assert definedRegisters == null || registers.equals(definedRegisters) : "cannot redefine";
         definedRegisters = registers;
     }
 
@@ -100,7 +103,6 @@
         super(runtime, replacements, target);
         this.stubInfo = snippet(getClass(), methodName);
         this.linkage = linkage;
-
     }
 
     /**
@@ -123,6 +125,15 @@
         return linkage;
     }
 
+    private boolean checkCompilationResult(CompilationResult compResult) {
+        for (DataPatch data : compResult.getDataReferences()) {
+            Constant constant = data.constant;
+            assert constant.getKind() != Kind.Object : MetaUtil.format("%h.%n(%p): ", getMethod()) + "cannot have embedded oop: " + constant;
+            assert constant.getPrimitiveAnnotation() == null : MetaUtil.format("%h.%n(%p): ", getMethod()) + "cannot have embedded metadata: " + constant;
+        }
+        return true;
+    }
+
     /**
      * Gets the code for this stub, compiling it first if necessary.
      */
@@ -143,6 +154,8 @@
                     final CompilationResult compResult = GraalCompiler.compileMethod(runtime(), replacements, backend, runtime().getTarget(), getMethod(), graph, null, phasePlan,
                                     OptimisticOptimizations.ALL, new SpeculationLog());
 
+                    assert checkCompilationResult(compResult);
+
                     assert definedRegisters != null;
                     code = Debug.scope("CodeInstall", new Callable<InstalledCode>() {
 
@@ -156,7 +169,6 @@
                             return installedCode;
                         }
                     });
-
                 }
             });
             assert code != null : "error installing stub " + getMethod();
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Sun Apr 28 22:52:12 2013 +0200
@@ -34,7 +34,6 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.api.meta.ResolvedJavaType.Representation;
 import com.oracle.graal.bytecode.*;
@@ -798,12 +797,7 @@
         if (!optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) {
             return null;
         } else {
-            ResolvedJavaType uniqueSubtype = type.findUniqueConcreteSubtype();
-            if (uniqueSubtype != null) {
-                return new JavaTypeProfile(profilingInfo.getNullSeen(bci()), 0.0D, new ProfiledType(uniqueSubtype, 1.0D));
-            } else {
-                return profilingInfo.getTypeProfile(bci());
-            }
+            return profilingInfo.getTypeProfile(bci());
         }
     }
 
@@ -812,7 +806,8 @@
         JavaType type = lookupType(cpi, CHECKCAST);
         ValueNode object = frameState.apop();
         if (type instanceof ResolvedJavaType) {
-            CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) type, object, getProfileForTypeCheck((ResolvedJavaType) type)));
+            JavaTypeProfile profileForTypeCheck = getProfileForTypeCheck((ResolvedJavaType) type);
+            CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) type, object, profileForTypeCheck));
             append(checkCast);
             frameState.apush(checkCast);
         } else {
@@ -1165,6 +1160,10 @@
         if (graphBuilderConfig.eagerResolving()) {
             returnType = returnType.resolve(targetMethod.getDeclaringClass());
         }
+        if (invokeKind != InvokeKind.Static && invokeKind != InvokeKind.Special) {
+            JavaTypeProfile profile = profilingInfo.getTypeProfile(bci());
+            args[0] = TypeProfileProxyNode.create(args[0], profile);
+        }
         MethodCallTargetNode callTarget = currentGraph.add(new MethodCallTargetNode(invokeKind, targetMethod, args, returnType));
         createInvokeNode(callTarget, resultType);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_currentTimeMillis02.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_currentTimeMillis02.java	Sun Apr 28 22:52:12 2013 +0200
@@ -36,8 +36,8 @@
             delta = System.currentTimeMillis() - start;
             // do nothing.
         }
-        // better get at least 40 millisecond resolution.
-        return delta >= 1 && delta < 40;
+        // better get at least 100 millisecond resolution.
+        return delta >= 1 && delta < 100;
     }
 
     @Test
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Reflection_getCallerClass01.java	Sun Apr 28 22:34:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2007, 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.jtt.reflect;
-
-import com.oracle.graal.jtt.*;
-import org.junit.*;
-
-import sun.reflect.*;
-
-/*
- */
-public final class Reflection_getCallerClass01 extends JTTTest {
-
-    public static final class Caller1 {
-
-        private Caller1() {
-        }
-
-        static String caller1(int depth) {
-            return Reflection.getCallerClass(depth).getName();
-        }
-    }
-
-    public static final class Caller2 {
-
-        private Caller2() {
-        }
-
-        static String caller2(int depth) {
-            return Caller1.caller1(depth);
-        }
-    }
-
-    public static String test(int depth) {
-        return Caller2.caller2(depth);
-    }
-
-    @Test
-    public void run0() throws Throwable {
-        runTest("test", 0);
-    }
-
-    @Test
-    public void run1() throws Throwable {
-        runTest("test", 1);
-    }
-
-    @Test
-    public void run2() throws Throwable {
-        runTest("test", 2);
-    }
-
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Sun Apr 28 22:52:12 2013 +0200
@@ -30,18 +30,19 @@
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.asm.amd64.AMD64Address.Scale;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 
 public class AMD64AddressValue extends CompositeValue {
 
     private static final long serialVersionUID = -4444600052487578694L;
 
-    @Component({REG, UNUSED}) protected AllocatableValue base;
-    @Component({REG, UNUSED}) protected AllocatableValue index;
+    @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue base;
+    @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue index;
     protected final Scale scale;
     protected final int displacement;
 
     public AMD64AddressValue(Kind kind, AllocatableValue base, int displacement) {
-        this(kind, base, AllocatableValue.UNUSED, Scale.Times1, displacement);
+        this(kind, base, Value.ILLEGAL, Scale.Times1, displacement);
     }
 
     public AMD64AddressValue(Kind kind, AllocatableValue base, AllocatableValue index, Scale scale, int displacement) {
@@ -53,7 +54,7 @@
     }
 
     private static Register toRegister(AllocatableValue value) {
-        if (value == AllocatableValue.UNUSED) {
+        if (value == Value.ILLEGAL) {
             return Register.None;
         } else {
             RegisterValue reg = (RegisterValue) value;
@@ -67,8 +68,7 @@
 
     @Override
     public String toString() {
-        StringBuilder s = new StringBuilder();
-        s.append(getKind().getJavaName()).append("[");
+        StringBuilder s = new StringBuilder("[");
         String sep = "";
         if (isLegal(base)) {
             s.append(base);
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Sun Apr 28 22:52:12 2013 +0200
@@ -26,7 +26,6 @@
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import com.oracle.graal.amd64.*;
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.graph.*;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java	Sun Apr 28 22:52:12 2013 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.lir.amd64;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.asm.*;
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Sun Apr 28 22:52:12 2013 +0200
@@ -44,10 +44,10 @@
     @Opcode("MOVE")
     public static class MoveToRegOp extends AMD64LIRInstruction implements MoveOp {
 
-        @Def({REG, HINT}) protected Value result;
+        @Def({REG, HINT}) protected AllocatableValue result;
         @Use({REG, STACK, CONST}) protected Value input;
 
-        public MoveToRegOp(Value result, Value input) {
+        public MoveToRegOp(AllocatableValue result, Value input) {
             this.result = result;
             this.input = input;
         }
@@ -63,7 +63,7 @@
         }
 
         @Override
-        public Value getResult() {
+        public AllocatableValue getResult() {
             return result;
         }
     }
@@ -71,10 +71,10 @@
     @Opcode("MOVE")
     public static class MoveFromRegOp extends AMD64LIRInstruction implements MoveOp {
 
-        @Def({REG, STACK}) protected Value result;
+        @Def({REG, STACK}) protected AllocatableValue result;
         @Use({REG, CONST, HINT}) protected Value input;
 
-        public MoveFromRegOp(Value result, Value input) {
+        public MoveFromRegOp(AllocatableValue result, Value input) {
             this.result = result;
             this.input = input;
         }
@@ -90,17 +90,19 @@
         }
 
         @Override
-        public Value getResult() {
+        public AllocatableValue getResult() {
             return result;
         }
     }
 
     public abstract static class MemOp extends AMD64LIRInstruction {
 
+        protected final Kind kind;
         @Use({COMPOSITE}) protected AMD64AddressValue address;
         @State protected LIRFrameState state;
 
-        public MemOp(AMD64AddressValue address, LIRFrameState state) {
+        public MemOp(Kind kind, AMD64AddressValue address, LIRFrameState state) {
+            this.kind = kind;
             this.address = address;
             this.state = state;
         }
@@ -120,14 +122,14 @@
 
         @Def({REG}) protected AllocatableValue result;
 
-        public LoadOp(AllocatableValue result, AMD64AddressValue address, LIRFrameState state) {
-            super(address, state);
+        public LoadOp(Kind kind, AllocatableValue result, AMD64AddressValue address, LIRFrameState state) {
+            super(kind, address, state);
             this.result = result;
         }
 
         @Override
         public void emitMemAccess(AMD64MacroAssembler masm) {
-            switch (address.getKind()) {
+            switch (kind) {
                 case Boolean:
                 case Byte:
                     masm.movsxb(asRegister(result), address.toAddress());
@@ -163,15 +165,15 @@
 
         @Use({REG}) protected AllocatableValue input;
 
-        public StoreOp(AMD64AddressValue address, AllocatableValue input, LIRFrameState state) {
-            super(address, state);
+        public StoreOp(Kind kind, AMD64AddressValue address, AllocatableValue input, LIRFrameState state) {
+            super(kind, address, state);
             this.input = input;
         }
 
         @Override
         public void emitMemAccess(AMD64MacroAssembler masm) {
             assert isRegister(input);
-            switch (address.getKind()) {
+            switch (kind) {
                 case Boolean:
                 case Byte:
                     masm.movb(address.toAddress(), asRegister(input));
@@ -205,14 +207,14 @@
 
         protected final Constant input;
 
-        public StoreConstantOp(AMD64AddressValue address, Constant input, LIRFrameState state) {
-            super(address, state);
+        public StoreConstantOp(Kind kind, AMD64AddressValue address, Constant input, LIRFrameState state) {
+            super(kind, address, state);
             this.input = input;
         }
 
         @Override
         public void emitMemAccess(AMD64MacroAssembler masm) {
-            switch (address.getKind()) {
+            switch (kind) {
                 case Boolean:
                 case Byte:
                     masm.movb(address.toAddress(), input.asInt() & 0xFF);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RegisterPreservationOp.java	Sun Apr 28 22:52:12 2013 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Base class for the operations that save or restore registers around another operation that may
+ * potentially destroy any register (e.g., a call).
+ */
+public abstract class AMD64RegisterPreservationOp extends AMD64LIRInstruction {
+
+    protected static void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value[] dst, Value[] src) {
+        for (int i = 0; i < dst.length; i++) {
+            if (dst[i] != null) {
+                AMD64Move.move(tasm, masm, dst[i], src[i]);
+            } else {
+                assert src[i] == null;
+            }
+        }
+    }
+
+    protected static void doNotPreserve(Set<Register> registers, RegisterValue[] registerValues, StackSlot[] slots) {
+        for (int i = 0; i < slots.length; i++) {
+            if (registerValues[i] != null) {
+                if (registers.contains(registerValues[i].getRegister())) {
+                    registerValues[i] = null;
+                    slots[i] = null;
+                }
+            }
+        }
+    }
+
+    /**
+     * Records that no registers in {@code registers} need to be preserved.
+     */
+    public abstract void doNotPreserve(Set<Register> registers);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RestoreRegistersOp.java	Sun Apr 28 22:52:12 2013 +0200
@@ -0,0 +1,84 @@
+/*
+ * 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.lir.amd64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Restores registers from stack slots.
+ */
+@Opcode("RESTORE_REGISTER")
+public final class AMD64RestoreRegistersOp extends AMD64RegisterPreservationOp {
+
+    @Use(STACK) protected StackSlot[] src;
+    @Def(REG) protected RegisterValue[] dst;
+
+    public AMD64RestoreRegistersOp(StackSlot[] src, RegisterValue[] dst) {
+        this.src = src;
+        this.dst = dst;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        emitCode(tasm, masm, dst, src);
+    }
+
+    @Override
+    public void doNotPreserve(Set<Register> registers) {
+        doNotPreserve(registers, dst, src);
+    }
+
+    /**
+     * Updates {@code debugInfo} with a description of where each preserved register is saved.
+     */
+    public void describePreservation(DebugInfo debugInfo, FrameMap frameMap) {
+        int preserved = 0;
+        for (RegisterValue r : dst) {
+            if (r != null) {
+                preserved++;
+            }
+        }
+        if (preserved != 0) {
+            Register[] keys = new Register[preserved];
+            int[] values = new int[keys.length];
+            int mapIndex = 0;
+            for (int i = 0; i < src.length; i++) {
+                if (dst[i] != null) {
+                    keys[mapIndex] = dst[i].getRegister();
+                    values[mapIndex] = frameMap.indexForStackSlot(src[i]);
+                    mapIndex++;
+                }
+            }
+            assert mapIndex == preserved;
+            debugInfo.setCalleeSaveInfo(new RegisterSaveLayout(keys, values));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java	Sun Apr 28 22:52:12 2013 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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.lir.amd64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Saves registers to stack slots.
+ */
+@Opcode("SAVE_REGISTER")
+public final class AMD64SaveRegistersOp extends AMD64RegisterPreservationOp {
+
+    @Use(REG) protected RegisterValue[] src;
+    @Def(STACK) protected StackSlot[] dst;
+
+    public AMD64SaveRegistersOp(RegisterValue[] src, StackSlot[] dst) {
+        this.src = src;
+        this.dst = dst;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        emitCode(tasm, masm, dst, src);
+    }
+
+    @Override
+    public void doNotPreserve(Set<Register> registers) {
+        doNotPreserve(registers, src, dst);
+    }
+
+}
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java	Sun Apr 28 22:52:12 2013 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.ptx.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 
 /**
  * Represents an address in target machine memory, specified via some combination of a base register
@@ -38,7 +39,7 @@
 
     private static final long serialVersionUID = 1802222435353022623L;
 
-    @Component({REG, UNUSED}) private AllocatableValue base;
+    @Component({REG, OperandFlag.ILLEGAL}) private AllocatableValue base;
     private final long displacement;
 
     /**
@@ -68,7 +69,7 @@
     }
 
     public PTXAddress toAddress() {
-        Register baseReg = base == AllocatableValue.UNUSED ? Register.None : asRegister(base);
+        Register baseReg = base == Value.ILLEGAL ? Register.None : asRegister(base);
         return new PTXAddress(baseReg, displacement);
     }
 
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXArithmetic.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXArithmetic.java	Sun Apr 28 22:52:12 2013 +0200
@@ -25,7 +25,6 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.ptx.*;
 import com.oracle.graal.graph.*;
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java	Sun Apr 28 22:52:12 2013 +0200
@@ -97,6 +97,7 @@
 
     @SuppressWarnings("unused")
     public static class CondMoveOp extends PTXLIRInstruction {
+
         @Def({REG, HINT}) protected Value result;
         @Alive({REG}) protected Value trueValue;
         @Use({REG, STACK, CONST}) protected Value falseValue;
@@ -119,6 +120,7 @@
 
     @SuppressWarnings("unused")
     public static class FloatCondMoveOp extends PTXLIRInstruction {
+
         @Def({REG}) protected Value result;
         @Alive({REG}) protected Value trueValue;
         @Alive({REG}) protected Value falseValue;
@@ -142,14 +144,14 @@
     }
 
     public static class SequentialSwitchOp extends PTXLIRInstruction implements FallThroughOp {
+
         @Use({CONST}) protected Constant[] keyConstants;
         private final LabelRef[] keyTargets;
         private LabelRef defaultTarget;
         @Alive({REG}) protected Value key;
         @Temp({REG, ILLEGAL}) protected Value scratch;
 
-        public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget,
-                                  Value key, Value scratch) {
+        public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) {
             assert keyConstants.length == keyTargets.length;
             this.keyConstants = keyConstants;
             this.keyTargets = keyTargets;
@@ -216,14 +218,14 @@
     }
 
     public static class TableSwitchOp extends PTXLIRInstruction {
+
         private final int lowKey;
         private final LabelRef defaultTarget;
         private final LabelRef[] targets;
         @Alive protected Value index;
         @Temp protected Value scratch;
 
-        public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets,
-                             Variable index, Variable scratch) {
+        public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, Variable index, Variable scratch) {
             this.lowKey = lowKey;
             this.defaultTarget = defaultTarget;
             this.targets = targets;
@@ -238,9 +240,7 @@
     }
 
     @SuppressWarnings("unused")
-    private static void tableswitch(TargetMethodAssembler tasm, PTXAssembler masm, int lowKey,
-                                    LabelRef defaultTarget, LabelRef[] targets,
-                                    Register value, Register scratch) {
+    private static void tableswitch(TargetMethodAssembler tasm, PTXAssembler masm, int lowKey, LabelRef defaultTarget, LabelRef[] targets, Register value, Register scratch) {
         Buffer buf = masm.codeBuffer;
         // Compare index against jump table bounds
         int highKey = lowKey + targets.length - 1;
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java	Sun Apr 28 22:52:12 2013 +0200
@@ -39,10 +39,10 @@
     @Opcode("MOVE")
     public static class SpillMoveOp extends PTXLIRInstruction implements MoveOp {
 
-        @Def({REG, STACK}) protected Value result;
+        @Def({REG, STACK}) protected AllocatableValue result;
         @Use({REG, STACK, CONST}) protected Value input;
 
-        public SpillMoveOp(Value result, Value input) {
+        public SpillMoveOp(AllocatableValue result, Value input) {
             this.result = result;
             this.input = input;
         }
@@ -58,7 +58,7 @@
         }
 
         @Override
-        public Value getResult() {
+        public AllocatableValue getResult() {
             return result;
         }
     }
@@ -66,10 +66,10 @@
     @Opcode("MOVE")
     public static class MoveToRegOp extends PTXLIRInstruction implements MoveOp {
 
-        @Def({REG, HINT}) protected Value result;
+        @Def({REG, HINT}) protected AllocatableValue result;
         @Use({REG, STACK, CONST}) protected Value input;
 
-        public MoveToRegOp(Value result, Value input) {
+        public MoveToRegOp(AllocatableValue result, Value input) {
             this.result = result;
             this.input = input;
         }
@@ -85,7 +85,7 @@
         }
 
         @Override
-        public Value getResult() {
+        public AllocatableValue getResult() {
             return result;
         }
     }
@@ -93,10 +93,10 @@
     @Opcode("MOVE")
     public static class MoveFromRegOp extends PTXLIRInstruction implements MoveOp {
 
-        @Def({REG, STACK}) protected Value result;
+        @Def({REG, STACK}) protected AllocatableValue result;
         @Use({REG, CONST, HINT}) protected Value input;
 
-        public MoveFromRegOp(Value result, Value input) {
+        public MoveFromRegOp(AllocatableValue result, Value input) {
             this.result = result;
             this.input = input;
         }
@@ -112,18 +112,20 @@
         }
 
         @Override
-        public Value getResult() {
+        public AllocatableValue getResult() {
             return result;
         }
     }
 
     public static class LoadOp extends PTXLIRInstruction {
 
+        private final Kind kind;
         @Def({REG}) protected AllocatableValue result;
         @Use({COMPOSITE}) protected PTXAddressValue address;
         @State protected LIRFrameState state;
 
-        public LoadOp(AllocatableValue result, PTXAddressValue address, LIRFrameState state) {
+        public LoadOp(Kind kind, AllocatableValue result, PTXAddressValue address, LIRFrameState state) {
+            this.kind = kind;
             this.result = result;
             this.address = address;
             this.state = state;
@@ -132,7 +134,7 @@
         @Override
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
             PTXAddress addr = address.toAddress();
-            switch (address.getKind()) {
+            switch (kind) {
                 case Byte:
                     masm.ld_global_s8(asRegister(result), addr.getBase(), addr.getDisplacement());
                     break;
@@ -165,11 +167,13 @@
 
     public static class StoreOp extends PTXLIRInstruction {
 
+        private final Kind kind;
         @Use({COMPOSITE}) protected PTXAddressValue address;
         @Use({REG}) protected AllocatableValue input;
         @State protected LIRFrameState state;
 
-        public StoreOp(PTXAddressValue address, AllocatableValue input, LIRFrameState state) {
+        public StoreOp(Kind kind, PTXAddressValue address, AllocatableValue input, LIRFrameState state) {
+            this.kind = kind;
             this.address = address;
             this.input = input;
             this.state = state;
@@ -179,7 +183,7 @@
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
             assert isRegister(input);
             PTXAddress addr = address.toAddress();
-            switch (address.getKind()) {
+            switch (kind) {
                 case Byte:
                     masm.st_global_s8(addr.getBase(), addr.getDisplacement(), asRegister(input));
                     break;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Sun Apr 28 22:52:12 2013 +0200
@@ -210,8 +210,7 @@
     }
 
     /**
-     * Computes the offset of a stack slot relative to the frame register. This is also the bit
-     * index of stack slots in the reference map.
+     * Computes the offset of a stack slot relative to the frame register.
      * 
      * @param slot a stack slot
      * @return the offset of the stack slot
@@ -226,6 +225,18 @@
     }
 
     /**
+     * Computes the index of a stack slot relative to slot 0. This is also the bit index of stack
+     * slots in the reference map.
+     * 
+     * @param slot a stack slot
+     * @return the index of the stack slot
+     */
+    public int indexForStackSlot(StackSlot slot) {
+        assert offsetForStackSlot(slot) % target.wordSize == 0;
+        return offsetForStackSlot(slot) / target.wordSize;
+    }
+
+    /**
      * Gets the offset to the stack area where callee-saved registers are stored.
      * 
      * @return The offset to the callee save area (in bytes).
@@ -285,7 +296,7 @@
         return getSlot(kind, 0);
     }
 
-    private List<StackSlot> freedSlots;
+    private Set<StackSlot> freedSlots;
 
     /**
      * Frees a spill slot that was obtained via {@link #allocateSpillSlot(Kind)} such that it can be
@@ -293,7 +304,7 @@
      */
     public void freeSpillSlot(StackSlot slot) {
         if (freedSlots == null) {
-            freedSlots = new ArrayList<>();
+            freedSlots = new HashSet<>();
         }
         freedSlots.add(slot);
     }
@@ -329,11 +340,6 @@
         }
     }
 
-    private int frameRefMapIndex(StackSlot slot) {
-        assert offsetForStackSlot(slot) % target.wordSize == 0;
-        return offsetForStackSlot(slot) / target.wordSize;
-    }
-
     /**
      * Initializes a reference map that covers all registers of the target architecture.
      */
@@ -368,7 +374,7 @@
             if (isRegister(location)) {
                 registerRefMap.set(asRegister(location).number);
             } else if (isStackSlot(location)) {
-                int index = frameRefMapIndex(asStackSlot(location));
+                int index = indexForStackSlot(asStackSlot(location));
                 frameRefMap.set(index);
             } else {
                 assert isConstant(location);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Sun Apr 28 22:52:12 2013 +0200
@@ -64,7 +64,7 @@
 
     public interface SpillMoveFactory {
 
-        LIRInstruction createMove(Value result, Value input);
+        LIRInstruction createMove(AllocatableValue result, Value input);
     }
 
     private boolean hasArgInCallerFrame;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Sun Apr 28 22:52:12 2013 +0200
@@ -181,11 +181,6 @@
         ILLEGAL,
 
         /**
-         * The value can be {@link AllocatableValue#UNUSED}.
-         */
-        UNUSED,
-
-        /**
          * The register allocator should try to assign a certain register to improve code quality.
          * Use {@link LIRInstruction#forEachRegisterHint} to access the register hints.
          */
@@ -205,10 +200,10 @@
 
     static {
         ALLOWED_FLAGS = new EnumMap<>(OperandMode.class);
-        ALLOWED_FLAGS.put(USE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNUSED, UNINITIALIZED));
-        ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNUSED, UNINITIALIZED));
-        ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, COMPOSITE, CONST, ILLEGAL, UNUSED, HINT));
-        ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, UNUSED, HINT));
+        ALLOWED_FLAGS.put(USE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED));
+        ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED));
+        ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, COMPOSITE, CONST, ILLEGAL, HINT));
+        ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, HINT));
     }
 
     /**
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Sun Apr 28 22:52:12 2013 +0200
@@ -232,8 +232,7 @@
 
     private static Value allowed(Object op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
         if ((isVariable(value) && flags.contains(OperandFlag.REG)) || (isRegister(value) && flags.contains(OperandFlag.REG)) || (isStackSlot(value) && flags.contains(OperandFlag.STACK)) ||
-                        (isConstant(value) && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) || (isIllegal(value) && flags.contains(OperandFlag.ILLEGAL)) ||
-                        (value == AllocatableValue.UNUSED && flags.contains(OperandFlag.UNUSED))) {
+                        (isConstant(value) && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) || (isIllegal(value) && flags.contains(OperandFlag.ILLEGAL))) {
             return value;
         }
         TTY.println("instruction %s", op);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,14 +22,14 @@
  */
 package com.oracle.graal.lir;
 
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.cfg.*;
 
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
 /**
  * A collection of machine-independent LIR operations, as well as interfaces to be implemented for
  * specific kinds or LIR operations.
@@ -117,7 +117,7 @@
 
         Value getInput();
 
-        Value getResult();
+        AllocatableValue getResult();
     }
 
     /**
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java	Sun Apr 28 22:52:12 2013 +0200
@@ -113,7 +113,7 @@
 
             Debug.metric("TargetMethods").increment();
             Debug.metric("CodeBytesEmitted").add(compilationResult.getTargetCodeSize());
-            Debug.metric("SafepointsEmitted").add(compilationResult.getInfopoints().size());
+            Debug.metric("InfopointsEmitted").add(compilationResult.getInfopoints().size());
             Debug.metric("DataPatches").add(ldp.size());
             Debug.metric("ExceptionHandlersEmitted").add(compilationResult.getExceptionHandlers().size());
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -25,10 +25,14 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
@@ -146,18 +150,169 @@
                 tool.deleteBranch(falseSuccessor());
                 tool.addToWorkList(trueSuccessor());
                 ((StructuredGraph) graph()).removeSplit(this, trueSuccessor());
+                return;
             } else {
                 tool.deleteBranch(trueSuccessor());
                 tool.addToWorkList(falseSuccessor());
                 ((StructuredGraph) graph()).removeSplit(this, falseSuccessor());
+                return;
             }
-        } else if (trueSuccessor().guards().isEmpty() && falseSuccessor().guards().isEmpty()) {
-            if (!removeOrMaterializeIf(tool)) {
-                removeIntermediateMaterialization(tool);
+        } else if (trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty()) {
+
+            if (removeOrMaterializeIf(tool)) {
+                return;
+            }
+        }
+
+        if (removeIntermediateMaterialization(tool)) {
+            return;
+        }
+
+        if (falseSuccessor().usages().isEmpty() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode) {
+            BeginNode intermediateBegin = falseSuccessor();
+            IfNode nextIf = (IfNode) intermediateBegin.next();
+            double probabilityB = (1.0 - this.trueSuccessorProbability) * nextIf.trueSuccessorProbability;
+            if (this.trueSuccessorProbability < probabilityB) {
+                // Reordering of those two if statements is beneficial from the point of view of
+                // their probabilities.
+                if (prepareForSwap(tool.runtime(), condition(), nextIf.condition(), this.trueSuccessorProbability, probabilityB)) {
+                    // Reording is allowed from (if1 => begin => if2) to (if2 => begin => if1).
+                    assert intermediateBegin.next() == nextIf;
+                    BeginNode bothFalseBegin = nextIf.falseSuccessor();
+                    nextIf.setFalseSuccessor(null);
+                    intermediateBegin.setNext(null);
+                    this.setFalseSuccessor(null);
+
+                    this.replaceAtPredecessor(nextIf);
+                    nextIf.setFalseSuccessor(intermediateBegin);
+                    intermediateBegin.setNext(this);
+                    this.setFalseSuccessor(bothFalseBegin);
+                    return;
+                }
             }
         }
     }
 
+    private static boolean prepareForSwap(MetaAccessProvider runtime, LogicNode a, LogicNode b, double probabilityA, double probabilityB) {
+        if (a instanceof InstanceOfNode) {
+            InstanceOfNode instanceOfA = (InstanceOfNode) a;
+            if (b instanceof IsNullNode) {
+                IsNullNode isNullNode = (IsNullNode) b;
+                if (isNullNode.object() == instanceOfA.object()) {
+                    if (instanceOfA.profile() != null && instanceOfA.profile().getNullSeen() != TriState.FALSE) {
+                        instanceOfA.setProfile(new JavaTypeProfile(TriState.FALSE, instanceOfA.profile().getNotRecordedProbability(), instanceOfA.profile().getTypes()));
+                    }
+                    Debug.log("Can swap instanceof and isnull if");
+                    return true;
+                }
+            } else if (b instanceof InstanceOfNode) {
+                InstanceOfNode instanceOfB = (InstanceOfNode) b;
+                if (instanceOfA.object() == instanceOfB.object() && !instanceOfA.type().isAssignableFrom(instanceOfB.type()) && !instanceOfB.type().isAssignableFrom(instanceOfA.type())) {
+                    // Two instanceof on the same value with mutually exclusive types.
+                    JavaTypeProfile profileA = instanceOfA.profile();
+                    JavaTypeProfile profileB = instanceOfB.profile();
+
+                    Debug.log("Can swap instanceof for types %s and %s", instanceOfA.type(), instanceOfB.type());
+                    JavaTypeProfile newProfile = null;
+                    if (profileA != null && profileB != null) {
+                        double remainder = 1.0;
+                        ArrayList<ProfiledType> profiledTypes = new ArrayList<>();
+                        for (ProfiledType type : profileB.getTypes()) {
+                            if (instanceOfB.type().isAssignableFrom(type.getType())) {
+                                // Do not add to profile.
+                            } else {
+                                ProfiledType newType = new ProfiledType(type.getType(), Math.min(1.0, type.getProbability() * (1.0 - probabilityA) / (1.0 - probabilityB)));
+                                profiledTypes.add(newType);
+                                remainder -= newType.getProbability();
+                            }
+                        }
+
+                        for (ProfiledType type : profileA.getTypes()) {
+                            if (instanceOfA.type().isAssignableFrom(type.getType())) {
+                                ProfiledType newType = new ProfiledType(type.getType(), Math.min(1.0, type.getProbability() / (1.0 - probabilityB)));
+                                profiledTypes.add(newType);
+                                remainder -= newType.getProbability();
+                            }
+                        }
+                        Collections.sort(profiledTypes);
+
+                        if (remainder < 0.0) {
+                            // Can happen due to round-off errors.
+                            remainder = 0.0;
+                        }
+                        newProfile = new JavaTypeProfile(profileB.getNullSeen(), remainder, profiledTypes.toArray(new ProfiledType[profiledTypes.size()]));
+                        Debug.log("First profile: %s", profileA);
+                        Debug.log("Original second profile: %s", profileB);
+                        Debug.log("New second profile: %s", newProfile);
+                    }
+                    instanceOfB.setProfile(profileA);
+                    instanceOfA.setProfile(newProfile);
+                    return true;
+                }
+            }
+        } else if (a instanceof CompareNode) {
+            CompareNode compareA = (CompareNode) a;
+            Condition conditionA = compareA.condition();
+            if (compareA.unorderedIsTrue()) {
+                return false;
+            }
+            if (b instanceof CompareNode) {
+                CompareNode compareB = (CompareNode) b;
+                if (compareA == compareB) {
+                    Debug.log("Same conditions => do not swap and leave the work for global value numbering.");
+                    return false;
+                }
+                if (compareB.unorderedIsTrue()) {
+                    return false;
+                }
+                Condition comparableCondition = null;
+                Condition conditionB = compareB.condition();
+                if (compareB.x() == compareA.x() && compareB.y() == compareA.y()) {
+                    comparableCondition = conditionB;
+                } else if (compareB.x() == compareA.y() && compareB.y() == compareA.x()) {
+                    comparableCondition = conditionB.mirror();
+                }
+
+                if (comparableCondition != null) {
+                    Condition combined = conditionA.join(comparableCondition);
+                    if (combined == null) {
+                        // The two conditions are disjoint => can reorder.
+                        Debug.log("Can swap disjoint coditions on same values: %s and %s", conditionA, comparableCondition);
+                        return true;
+                    }
+                } else if (conditionA == Condition.EQ && conditionB == Condition.EQ) {
+                    boolean canSwap = false;
+                    if ((compareA.x() == compareB.x() && valuesDistinct(runtime, compareA.y(), compareB.y()))) {
+                        canSwap = true;
+                    } else if ((compareA.x() == compareB.y() && valuesDistinct(runtime, compareA.y(), compareB.x()))) {
+                        canSwap = true;
+                    } else if ((compareA.y() == compareB.x() && valuesDistinct(runtime, compareA.x(), compareB.y()))) {
+                        canSwap = true;
+                    } else if ((compareA.y() == compareB.y() && valuesDistinct(runtime, compareA.x(), compareB.x()))) {
+                        canSwap = true;
+                    }
+
+                    if (canSwap) {
+                        Debug.log("Can swap equality condition with one shared and one disjoint value.");
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    private static boolean valuesDistinct(MetaAccessProvider runtime, ValueNode a, ValueNode b) {
+        if (a.isConstant() && b.isConstant()) {
+            return !runtime.constantEquals(a.asConstant(), b.asConstant());
+        }
+
+        Stamp stampA = a.stamp();
+        Stamp stampB = b.stamp();
+        return stampA.alwaysDistinct(stampB);
+    }
+
     /**
      * Tries to remove an empty if construct or replace an if construct with a materialization.
      * 
@@ -173,7 +328,7 @@
                 if (!phis.hasNext()) {
                     // empty if construct with no phis: remove it
                     removeEmptyIf(tool);
-                    return false;
+                    return true;
                 } else {
                     PhiNode singlePhi = phis.next();
                     if (!phis.hasNext()) {
@@ -260,11 +415,12 @@
             return false;
         }
 
-        MergeNode merge = (MergeNode) predecessor();
-        if (!merge.anchored().isEmpty()) {
+        if (predecessor() instanceof LoopBeginNode) {
             return false;
         }
 
+        MergeNode merge = (MergeNode) predecessor();
+
         // Only consider merges with a single usage that is both a phi and an operand of the
         // comparison
         NodeIterable<Node> mergeUsages = merge.usages();
@@ -289,10 +445,7 @@
         }
 
         List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
-        if (phi.valueCount() != merge.forwardEndCount()) {
-            // Handles a loop begin merge
-            return false;
-        }
+        assert phi.valueCount() == merge.forwardEndCount();
 
         Constant[] xs = constantValues(compare.x(), merge);
         Constant[] ys = constantValues(compare.y(), merge);
@@ -300,6 +453,11 @@
             return false;
         }
 
+        // Sanity check that both ends are not followed by a merge without frame state.
+        if (!checkFrameState(trueSuccessor()) && !checkFrameState(falseSuccessor())) {
+            return false;
+        }
+
         List<EndNode> falseEnds = new ArrayList<>(mergePredecessors.size());
         List<EndNode> trueEnds = new ArrayList<>(mergePredecessors.size());
         Map<EndNode, ValueNode> phiValues = new HashMap<>(mergePredecessors.size());
@@ -336,6 +494,45 @@
         return true;
     }
 
+    private static boolean checkFrameState(FixedNode start) {
+        FixedNode node = start;
+        while (true) {
+            if (node instanceof MergeNode) {
+                MergeNode mergeNode = (MergeNode) node;
+                if (mergeNode.stateAfter() == null) {
+                    return false;
+                } else {
+                    return true;
+                }
+            } else if (node instanceof StateSplit) {
+                StateSplit stateSplitNode = (StateSplit) node;
+                if (stateSplitNode.stateAfter() != null) {
+                    return true;
+                }
+            }
+
+            if (node instanceof ControlSplitNode) {
+                ControlSplitNode controlSplitNode = (ControlSplitNode) node;
+                for (Node succ : controlSplitNode.cfgSuccessors()) {
+                    if (checkFrameState((FixedNode) succ)) {
+                        return true;
+                    }
+                }
+                return false;
+            } else if (node instanceof FixedWithNextNode) {
+                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
+                node = fixedWithNextNode.next();
+            } else if (node instanceof EndNode) {
+                EndNode endNode = (EndNode) node;
+                node = endNode.merge();
+            } else if (node instanceof ControlSinkNode) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
     /**
      * Connects a set of ends to a given successor, inserting a merge node if there is more than one
      * end. If {@code ends} is empty, then {@code successor} is
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -144,7 +144,7 @@
         }
         if (node instanceof FixedWithNextNode) {
             ((StructuredGraph) graph()).replaceFixedWithFixed(this, (FixedWithNextNode) node);
-        } else if (node instanceof DeoptimizeNode) {
+        } else if (node instanceof ControlSinkNode) {
             this.replaceAtPredecessor(node);
             this.replaceAtUsages(null);
             GraphUtil.killCFG(this);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -188,7 +188,7 @@
         if (node == null) {
             assert kind() == Kind.Void && usages().isEmpty();
             ((StructuredGraph) graph()).removeSplit(this, next());
-        } else if (node instanceof DeoptimizeNode) {
+        } else if (node instanceof ControlSinkNode) {
             this.replaceAtPredecessor(node);
             this.replaceAtUsages(null);
             GraphUtil.killCFG(this);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -154,6 +154,10 @@
             if (this.anchored().isNotEmpty()) {
                 return;
             }
+            if (merge.stateAfter() == null && this.stateAfter() != null) {
+                // We hold a state, but the succeeding merge does not => do not combine.
+                return;
+            }
             for (PhiNode phi : phis()) {
                 for (Node usage : phi.usages().filter(isNotA(FrameState.class))) {
                     if (!merge.isPhiAtMerge(usage)) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2013, 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.nodes;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * A node that attached a type profile to a proxied input node.
+ */
+public final class TypeProfileProxyNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType {
+
+    @Input private ValueNode object;
+    private final JavaTypeProfile profile;
+    private transient ResolvedJavaType lastCheckedType;
+    private transient JavaTypeProfile lastCheckedProfile;
+
+    public ValueNode getObject() {
+        return object;
+    }
+
+    public static ValueNode create(ValueNode object, JavaTypeProfile profile) {
+        if (profile == null) {
+            // No profile, so create no node.
+            return object;
+        }
+        if (profile.getTypes().length == 0) {
+            // Only null profiling is not beneficial enough to keep the node around.
+            return object;
+        }
+        return object.graph().add(new TypeProfileProxyNode(object, profile));
+    }
+
+    private TypeProfileProxyNode(ValueNode object, JavaTypeProfile profile) {
+        super(object.stamp());
+        this.object = object;
+        this.profile = profile;
+    }
+
+    public JavaTypeProfile getProfile() {
+        return profile;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return object.inferStamp();
+    }
+
+    @Override
+    public Stamp stamp() {
+        return object.stamp();
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (object.objectStamp().isExactType()) {
+            // The profile is useless - we know the type!
+            return object;
+        } else if (object instanceof TypeProfileProxyNode) {
+            TypeProfileProxyNode other = (TypeProfileProxyNode) object;
+            JavaTypeProfile otherProfile = other.getProfile();
+            if (otherProfile == lastCheckedProfile) {
+                // We have already incorporated the knowledge about this profile => abort.
+                return this;
+            }
+            lastCheckedProfile = otherProfile;
+            JavaTypeProfile newProfile = this.profile.restrict(otherProfile);
+            if (newProfile.equals(otherProfile)) {
+                // We are useless - just use the other proxy node.
+                Debug.log("Canonicalize with other proxy node.");
+                return object;
+            }
+            if (newProfile != this.profile) {
+                Debug.log("Improved profile via other profile.");
+                return TypeProfileProxyNode.create(object, newProfile);
+            }
+        } else if (object.objectStamp().type() != null) {
+            ResolvedJavaType type = object.objectStamp().type();
+            ResolvedJavaType uniqueConcrete = type.findUniqueConcreteSubtype();
+            if (uniqueConcrete != null) {
+                // Profile is useless => remove.
+                Debug.log("Profile useless, there is enough static type information available.");
+                return object;
+            }
+            if (type == lastCheckedType) {
+                // We have already incorporate the knowledge about this type => abort.
+            }
+            lastCheckedType = type;
+            JavaTypeProfile newProfile = this.profile.restrict(type, object.objectStamp().nonNull());
+            if (newProfile != this.profile) {
+                Debug.log("Improved profile via static type information.");
+                if (newProfile.getTypes().length == 0) {
+                    // Only null profiling is not beneficial enough to keep the node around.
+                    return object;
+                }
+                return TypeProfileProxyNode.create(object, newProfile);
+            }
+        }
+        return this;
+    }
+
+    public static void cleanFromGraph(StructuredGraph graph) {
+        for (TypeProfileProxyNode proxy : graph.getNodes(TypeProfileProxyNode.class)) {
+            proxy.replaceAtUsages(proxy.getObject());
+        }
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -91,18 +91,6 @@
         return getY().generateAddress(gen, xAddr);
     }
 
-    @Override
-    public Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting) {
-        Value xAddr = getX().generateAddress(gen, base);
-        return getY().generateLoad(gen, xAddr, deopting);
-    }
-
-    @Override
-    public void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting) {
-        Value xAddr = getX().generateAddress(gen, base);
-        getY().generateStore(gen, xAddr, value, deopting);
-    }
-
     @NodeIntrinsic
     public static native Location addLocation(@ConstantNodeParameter Object identity, @ConstantNodeParameter Kind kind, Location x, Location y);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -56,16 +55,6 @@
 
     @Override
     public Value generateAddress(LIRGeneratorTool gen, Value base) {
-        return gen.emitLea(base, displacement(), Value.ILLEGAL, 0);
-    }
-
-    @Override
-    public Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting) {
-        return gen.emitLoad(getValueKind(), base, displacement(), Value.ILLEGAL, 0, deopting);
-    }
-
-    @Override
-    public void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting) {
-        gen.emitStore(getValueKind(), base, displacement(), Value.ILLEGAL, 0, value, deopting);
+        return gen.emitAddress(base, displacement(), Value.ILLEGAL, 0);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -24,6 +24,7 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -53,7 +54,8 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        gen.setResult(this, location().generateLoad(gen, gen.operand(object()), this));
+        Value address = location().generateAddress(gen, gen.operand(object()));
+        gen.setResult(this, gen.emitLoad(location().getValueKind(), address, this));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -91,17 +91,7 @@
 
     @Override
     public Value generateAddress(LIRGeneratorTool gen, Value base) {
-        return gen.emitLea(base, displacement, gen.operand(index()), indexScaling());
-    }
-
-    @Override
-    public Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting) {
-        return gen.emitLoad(getValueKind(), base, displacement, gen.operand(index()), indexScaling(), deopting);
-    }
-
-    @Override
-    public void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting) {
-        gen.emitStore(getValueKind(), base, displacement, gen.operand(index()), indexScaling(), value, deopting);
+        return gen.emitAddress(base, displacement, gen.operand(index()), indexScaling());
     }
 
     @NodeIntrinsic
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -0,0 +1,60 @@
+/*
+ * 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.nodes.extended;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Loads a method from the virtual method table of a given hub.
+ */
+public final class LoadMethodNode extends FixedWithNextNode implements Lowerable {
+
+    @Input private ValueNode hub;
+    private final ResolvedJavaMethod method;
+
+    public ValueNode getHub() {
+        return hub;
+    }
+
+    public LoadMethodNode(ResolvedJavaMethod method, ValueNode hub, Kind kind) {
+        super(kind == Kind.Object ? StampFactory.objectNonNull() : StampFactory.forKind(kind));
+        this.hub = hub;
+        this.method = method;
+        assert !Modifier.isAbstract(method.getModifiers()) : "Cannot load abstract method from a hub";
+        assert !Modifier.isStatic(method.getModifiers()) : "Cannot load a static method from a hub";
+    }
+
+    @Override
+    public void lower(LoweringTool tool, LoweringType loweringType) {
+        tool.getRuntime().lower(this, tool);
+    }
+
+    public ResolvedJavaMethod getMethod() {
+        return method;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node.ValueNumberable;
-import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -100,8 +99,4 @@
     }
 
     public abstract Value generateAddress(LIRGeneratorTool gen, Value base);
-
-    public abstract Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting);
-
-    public abstract void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -57,7 +57,8 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        gen.setResult(this, location().generateLoad(gen, gen.operand(object()), this));
+        Value address = location().generateAddress(gen, gen.operand(object()));
+        gen.setResult(this, gen.emitLoad(location().getValueKind(), address, this));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -91,7 +91,7 @@
     public void generate(LIRGeneratorTool generator) {
         if (kind() != object().kind()) {
             assert generator.target().sizeInBytes(kind()) == generator.target().sizeInBytes(object().kind()) : "unsafe cast cannot be used to change the size of a value";
-            Value result = generator.newVariable(kind());
+            AllocatableValue result = generator.newVariable(kind());
             generator.emitMove(result, generator.operand(object()));
             generator.setResult(this, result);
         } else {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,10 +22,11 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.graph.*;
 
 /**
  * Writes a given {@linkplain #value() value} a {@linkplain AccessNode memory location}.
@@ -84,7 +85,8 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        location().generateStore(gen, gen.operand(object()), gen.operand(value()), this);
+        Value address = location().generateAddress(gen, gen.operand(object()));
+        gen.emitStore(location().getValueKind(), address, gen.operand(value()), this);
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -80,7 +80,7 @@
     @Override
     public boolean verify() {
         for (Node usage : usages()) {
-            assertTrue(usage instanceof IfNode || usage instanceof ConditionalNode, "unsupported usage: %s", usage);
+            assertTrue(usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ConditionalNode, "unsupported usage: %s", usage);
         }
         return super.verify();
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -36,7 +36,7 @@
 
     @Input private ValueNode object;
     private final ResolvedJavaType type;
-    private final JavaTypeProfile profile;
+    private JavaTypeProfile profile;
 
     /**
      * Constructs a new InstanceOfNode.
@@ -109,10 +109,14 @@
         return profile;
     }
 
+    public void setProfile(JavaTypeProfile profile) {
+        this.profile = profile;
+    }
+
     @Override
     public boolean verify() {
         for (Node usage : usages()) {
-            assertTrue(usage instanceof IfNode || usage instanceof ConditionalNode, "unsupported usage: ", usage);
+            assertTrue(usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ConditionalNode, "unsupported usage: ", usage);
         }
         return super.verify();
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes.java;
 
+import java.lang.reflect.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -102,6 +104,14 @@
         for (Node n : usages()) {
             assertTrue(n instanceof Invoke, "call target can only be used from an invoke (%s)", n);
         }
+        if (invokeKind == InvokeKind.Special || invokeKind == InvokeKind.Static) {
+            assertFalse(Modifier.isAbstract(targetMethod.getModifiers()), "special calls or static calls are only allowed for concrete methods (%s)", targetMethod);
+        }
+        if (invokeKind == InvokeKind.Static) {
+            assertTrue(Modifier.isStatic(targetMethod.getModifiers()), "static calls are only allowed for static methods (%s)", targetMethod);
+        } else {
+            assertFalse(Modifier.isStatic(targetMethod.getModifiers()), "static calls are only allowed for non-static methods (%s)", targetMethod);
+        }
         return super.verify();
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Sun Apr 28 22:52:12 2013 +0200
@@ -29,11 +29,11 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 
-public abstract class LIRGeneratorTool {
+public interface LIRGeneratorTool {
 
-    public abstract TargetDescription target();
+    TargetDescription target();
 
-    public abstract CodeCacheProvider getRuntime();
+    CodeCacheProvider getRuntime();
 
     /**
      * Checks whether the supplied constant can be used without loading it into a register for most
@@ -43,100 +43,99 @@
      * @return True if the constant can be used directly, false if the constant needs to be in a
      *         register.
      */
-    public abstract boolean canInlineConstant(Constant c);
+    boolean canInlineConstant(Constant c);
 
-    public abstract RegisterAttributes attributes(Register register);
+    RegisterAttributes attributes(Register register);
 
-    public abstract Value operand(ValueNode object);
+    Value operand(ValueNode object);
 
-    public abstract AllocatableValue newVariable(Kind kind);
+    AllocatableValue newVariable(Kind kind);
 
-    public abstract Value setResult(ValueNode x, Value operand);
+    Value setResult(ValueNode x, Value operand);
 
-    public abstract Value emitMove(Value input);
+    AllocatableValue emitMove(Value input);
 
-    public abstract void emitMove(Value dst, Value src);
+    void emitMove(AllocatableValue dst, Value src);
 
-    public abstract Value emitLoad(Kind kind, Value base, long displacement, Value index, int scale, DeoptimizingNode deopting);
+    Value emitAddress(Value base, long displacement, Value index, int scale);
 
-    public abstract void emitStore(Kind kind, Value base, long displacement, Value index, int scale, Value input, DeoptimizingNode deopting);
+    Value emitAddress(StackSlot slot);
 
-    public abstract Value emitLea(Value base, long displacement, Value index, int scale);
+    Value emitLoad(Kind kind, Value address, DeoptimizingNode deopting);
 
-    public abstract Value emitLea(StackSlot slot);
+    void emitStore(Kind kind, Value address, Value input, DeoptimizingNode deopting);
 
-    public abstract Value emitNegate(Value input);
+    Value emitNegate(Value input);
 
-    public abstract Value emitAdd(Value a, Value b);
+    Value emitAdd(Value a, Value b);
 
-    public abstract Value emitSub(Value a, Value b);
+    Value emitSub(Value a, Value b);
 
-    public abstract Value emitMul(Value a, Value b);
+    Value emitMul(Value a, Value b);
 
-    public abstract Value emitDiv(Value a, Value b, DeoptimizingNode deopting);
+    Value emitDiv(Value a, Value b, DeoptimizingNode deopting);
 
-    public abstract Value emitRem(Value a, Value b, DeoptimizingNode deopting);
+    Value emitRem(Value a, Value b, DeoptimizingNode deopting);
 
-    public abstract Value emitUDiv(Value a, Value b, DeoptimizingNode deopting);
+    Value emitUDiv(Value a, Value b, DeoptimizingNode deopting);
 
-    public abstract Value emitURem(Value a, Value b, DeoptimizingNode deopting);
+    Value emitURem(Value a, Value b, DeoptimizingNode deopting);
 
-    public abstract Value emitAnd(Value a, Value b);
+    Value emitAnd(Value a, Value b);
 
-    public abstract Value emitOr(Value a, Value b);
+    Value emitOr(Value a, Value b);
 
-    public abstract Value emitXor(Value a, Value b);
+    Value emitXor(Value a, Value b);
 
-    public abstract Value emitShl(Value a, Value b);
+    Value emitShl(Value a, Value b);
 
-    public abstract Value emitShr(Value a, Value b);
+    Value emitShr(Value a, Value b);
 
-    public abstract Value emitUShr(Value a, Value b);
+    Value emitUShr(Value a, Value b);
 
-    public abstract Value emitConvert(ConvertNode.Op opcode, Value inputVal);
+    Value emitConvert(ConvertNode.Op opcode, Value inputVal);
 
-    public abstract void emitMembar(int barriers);
+    void emitMembar(int barriers);
 
-    public abstract void emitDeoptimize(DeoptimizationAction action, DeoptimizingNode deopting);
+    void emitDeoptimize(DeoptimizationAction action, DeoptimizingNode deopting);
 
-    public abstract void emitNullCheck(ValueNode v, DeoptimizingNode deopting);
+    void emitNullCheck(ValueNode v, DeoptimizingNode deopting);
 
-    public abstract Value emitCall(RuntimeCallTarget callTarget, CallingConvention cc, DeoptimizingNode info, Value... args);
+    Value emitCall(RuntimeCallTarget callTarget, CallingConvention cc, DeoptimizingNode info, Value... args);
 
-    public abstract void emitIf(IfNode i);
+    void emitIf(IfNode i);
 
-    public abstract void emitConditional(ConditionalNode i);
+    void emitConditional(ConditionalNode i);
 
-    public abstract void emitSwitch(SwitchNode i);
+    void emitSwitch(SwitchNode i);
 
-    public abstract void emitInvoke(Invoke i);
+    void emitInvoke(Invoke i);
 
-    public abstract void visitRuntimeCall(RuntimeCallNode i);
+    void visitRuntimeCall(RuntimeCallNode i);
 
     // Handling of block-end nodes still needs to be unified in the LIRGenerator.
-    public abstract void visitMerge(MergeNode i);
+    void visitMerge(MergeNode i);
 
-    public abstract void visitEndNode(EndNode i);
+    void visitEndNode(EndNode i);
 
-    public abstract void visitLoopEnd(LoopEndNode i);
+    void visitLoopEnd(LoopEndNode i);
 
-    public abstract void visitCompareAndSwap(CompareAndSwapNode i);
+    void visitCompareAndSwap(CompareAndSwapNode i);
 
     // These methods define the contract a runtime specific backend must provide.
 
-    public abstract void visitReturn(ReturnNode i);
+    void visitReturn(ReturnNode i);
 
-    public abstract void visitSafepointNode(SafepointNode i);
+    void visitSafepointNode(SafepointNode i);
 
-    public abstract void visitBreakpointNode(BreakpointNode i);
+    void visitBreakpointNode(BreakpointNode i);
 
-    public abstract void emitUnwind(Value operand);
+    void emitUnwind(Value operand);
 
     /**
      * Called just before register allocation is performed on the LIR owned by this generator.
      */
-    public void beforeRegisterAllocation() {
-    }
+    void beforeRegisterAllocation();
 
-    public abstract void visitInfopointNode(InfopointNode i);
+    void visitInfopointNode(InfopointNode i);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java	Sun Apr 28 22:52:12 2013 +0200
@@ -34,7 +34,7 @@
 
     Replacements getReplacements();
 
-    ValueNode createNullCheckGuard(ValueNode object);
+    ValueNode createNullCheckGuard(NodeInputList<ValueNode> dependencies, ValueNode object);
 
     ValueNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Sun Apr 28 22:52:12 2013 +0200
@@ -229,7 +229,7 @@
     public static RuntimeException approxSourceException(Node node, Throwable cause) {
         final StackTraceElement[] elements = approxSourceStackTraceElement(node);
         @SuppressWarnings("serial")
-        RuntimeException exception = new RuntimeException(cause.getMessage(), cause) {
+        RuntimeException exception = new RuntimeException((cause == null) ? null : cause.getMessage(), cause) {
 
             @Override
             public final synchronized Throwable fillInStackTrace() {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,14 +22,13 @@
  */
 package com.oracle.graal.phases.common;
 
-import java.util.*;
 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.graph.Graph.InputChangedListener;
+import com.oracle.graal.graph.Graph.NodeChangedListener;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
@@ -49,6 +48,7 @@
     public static final DebugMetric METRIC_GLOBAL_VALUE_NUMBERING_HITS = Debug.metric("GlobalValueNumberingHits");
 
     private final CustomCanonicalizer customCanonicalizer;
+    private final Iterable<Node> workingSet;
 
     public interface CustomCanonicalizer {
 
@@ -60,12 +60,17 @@
     }
 
     public CanonicalizerPhase(CustomCanonicalizer customCanonicalizer) {
+        this(customCanonicalizer, null);
+    }
+
+    public CanonicalizerPhase(CustomCanonicalizer customCanonicalizer, Iterable<Node> workingSet) {
         this.customCanonicalizer = customCanonicalizer;
+        this.workingSet = workingSet;
     }
 
     @Override
     protected void run(StructuredGraph graph, PhaseContext context) {
-        new Instance(context.getRuntime(), context.getAssumptions(), null, customCanonicalizer).run(graph);
+        new Instance(context.getRuntime(), context.getAssumptions(), workingSet, customCanonicalizer).run(graph);
     }
 
     public static class Instance extends Phase {
@@ -78,7 +83,6 @@
 
         private NodeWorkList workList;
         private Tool tool;
-        private List<Node> snapshotTemp;
 
         public Instance(MetaAccessProvider runtime, Assumptions assumptions) {
             this(runtime, assumptions, null, 0, null);
@@ -110,7 +114,6 @@
             this.runtime = runtime;
             this.customCanonicalizer = customCanonicalizer;
             this.initWorkingSet = workingSet;
-            this.snapshotTemp = new ArrayList<>();
         }
 
         @Override
@@ -129,19 +132,22 @@
         }
 
         private void processWorkSet(StructuredGraph graph) {
-            graph.trackInputChange(new InputChangedListener() {
+            NodeChangedListener nodeChangedListener = new NodeChangedListener() {
 
                 @Override
-                public void inputChanged(Node node) {
+                public void nodeChanged(Node node) {
                     workList.addAgain(node);
                 }
-            });
+            };
+            graph.trackInputChange(nodeChangedListener);
+            graph.trackUsagesDroppedZero(nodeChangedListener);
 
             for (Node n : workList) {
                 processNode(n, graph);
             }
 
             graph.stopTrackingInputChange();
+            graph.stopTrackingUsagesDroppedZero();
         }
 
         private void processNode(Node node, StructuredGraph graph) {
@@ -153,17 +159,9 @@
                 }
                 int mark = graph.getMark();
                 if (!tryKillUnused(node)) {
-                    node.inputs().filter(GraphUtil.isFloatingNode()).snapshotTo(snapshotTemp);
                     if (!tryCanonicalize(node, graph)) {
                         tryInferStamp(node, graph);
-                    } else {
-                        for (Node in : snapshotTemp) {
-                            if (in.isAlive() && in.usages().isEmpty()) {
-                                GraphUtil.killWithUnusedFloatingInputs(in);
-                            }
-                        }
                     }
-                    snapshotTemp.clear();
                 }
 
                 for (Node newNode : graph.getNewNodes(mark)) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Sun Apr 28 22:52:12 2013 +0200
@@ -27,7 +27,6 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 
@@ -78,22 +77,18 @@
             IfNode ifNode = (IfNode) deoptBegin.predecessor();
             BeginNode otherBegin = ifNode.trueSuccessor();
             LogicNode conditionNode = ifNode.condition();
-            if (!(conditionNode instanceof InstanceOfNode) && !(conditionNode instanceof InstanceOfDynamicNode)) {
-                // TODO The lowering currently does not support a FixedGuard as the usage of an
-                // InstanceOfNode. Relax this restriction.
-                FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), deoptBegin == ifNode.trueSuccessor()));
-                FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor();
-                if (deoptBegin == ifNode.trueSuccessor()) {
-                    graph.removeSplitPropagate(ifNode, ifNode.falseSuccessor());
-                } else {
-                    graph.removeSplitPropagate(ifNode, ifNode.trueSuccessor());
-                }
-                Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s.", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin);
-                FixedNode next = pred.next();
-                pred.setNext(guard);
-                guard.setNext(next);
-                return;
+            FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), deoptBegin == ifNode.trueSuccessor()));
+            FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor();
+            if (deoptBegin == ifNode.trueSuccessor()) {
+                graph.removeSplitPropagate(ifNode, ifNode.falseSuccessor());
+            } else {
+                graph.removeSplitPropagate(ifNode, ifNode.trueSuccessor());
             }
+            Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s.", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin);
+            FixedNode next = pred.next();
+            pred.setNext(guard);
+            guard.setNext(next);
+            return;
         }
 
         // We could not convert the control split - at least cut off control flow after the split.
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Sun Apr 28 22:52:12 2013 +0200
@@ -67,7 +67,8 @@
                 if (node instanceof DeoptimizingNode) {
                     DeoptimizingNode deopt = (DeoptimizingNode) node;
                     if (deopt.canDeoptimize() && deopt.getDeoptimizationState() == null) {
-                        deopt.setDeoptimizationState(currentState.getFramestate());
+                        FrameState state = currentState.getFramestate();
+                        deopt.setDeoptimizationState(state);
                     }
                 }
 
@@ -93,7 +94,7 @@
             if (merge.stateAfter() != null) {
                 return new FrameStateAssignmentState(merge.stateAfter());
             }
-            return new FrameStateAssignmentState(singleFrameState(states));
+            return new FrameStateAssignmentState(singleFrameState(merge, states));
         }
 
         @Override
@@ -125,15 +126,34 @@
         return true;
     }
 
-    private static FrameState singleFrameState(List<FrameStateAssignmentState> states) {
-        Iterator<FrameStateAssignmentState> it = states.iterator();
-        assert it.hasNext();
-        FrameState first = it.next().getFramestate();
-        while (it.hasNext()) {
-            if (first != it.next().getFramestate()) {
+    private static FrameState singleFrameState(@SuppressWarnings("unused") MergeNode merge, List<FrameStateAssignmentState> states) {
+        if (states.size() == 0) {
+            return null;
+        }
+        FrameState firstState = states.get(0).getFramestate();
+        FrameState singleState = firstState;
+        if (singleState == null) {
+            return null;
+        }
+        int singleBci = singleState.bci;
+        for (int i = 1; i < states.size(); ++i) {
+            FrameState cur = states.get(i).getFramestate();
+            if (cur == null) {
                 return null;
             }
+
+            if (cur != singleState) {
+                singleState = null;
+            }
+
+            if (cur.bci != singleBci) {
+                singleBci = FrameState.INVALID_FRAMESTATE_BCI;
+            }
+
         }
-        return first;
+        if (singleState != null) {
+            return singleState;
+        }
+        return null;
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Sun Apr 28 22:52:12 2013 +0200
@@ -144,6 +144,9 @@
                 }
             }
         }
+
+        // Clean up type profiles.
+        TypeProfileProxyNode.cleanFromGraph(graph);
     }
 
     @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Sun Apr 28 22:52:12 2013 +0200
@@ -42,6 +42,7 @@
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.*;
 
 public class InliningUtil {
 
@@ -254,6 +255,10 @@
             Class<? extends FixedWithNextNode> macroNodeClass = getMacroNodeClass(replacements, concrete);
             StructuredGraph graph = (StructuredGraph) invoke.asNode().graph();
             if (macroNodeClass != null) {
+                if (((MethodCallTargetNode) invoke.callTarget()).targetMethod() != concrete) {
+                    assert ((MethodCallTargetNode) invoke.callTarget()).invokeKind() != InvokeKind.Static;
+                    InliningUtil.replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete);
+                }
                 FixedWithNextNode macroNode;
                 try {
                     macroNode = macroNodeClass.getConstructor(Invoke.class).newInstance(invoke);
@@ -294,12 +299,12 @@
                 }
             });
         }
+    }
 
-        protected void replaceInvokeCallTarget(StructuredGraph graph, InvokeKind invokeKind, ResolvedJavaMethod targetMethod) {
-            MethodCallTargetNode oldCallTarget = (MethodCallTargetNode) invoke.callTarget();
-            MethodCallTargetNode newCallTarget = graph.add(new MethodCallTargetNode(invokeKind, targetMethod, oldCallTarget.arguments().toArray(new ValueNode[0]), oldCallTarget.returnType()));
-            invoke.asNode().replaceFirstInput(oldCallTarget, newCallTarget);
-        }
+    public static void replaceInvokeCallTarget(Invoke invoke, StructuredGraph graph, InvokeKind invokeKind, ResolvedJavaMethod targetMethod) {
+        MethodCallTargetNode oldCallTarget = (MethodCallTargetNode) invoke.callTarget();
+        MethodCallTargetNode newCallTarget = graph.add(new MethodCallTargetNode(invokeKind, targetMethod, oldCallTarget.arguments().toArray(new ValueNode[0]), oldCallTarget.returnType()));
+        invoke.asNode().replaceFirstInput(oldCallTarget, newCallTarget);
     }
 
     /**
@@ -378,7 +383,7 @@
         @Override
         public void tryToDevirtualizeInvoke(StructuredGraph graph, MetaAccessProvider runtime, Assumptions assumptions) {
             createGuard(graph, runtime);
-            replaceInvokeCallTarget(graph, InvokeKind.Special, concrete);
+            replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete);
         }
 
         private void createGuard(StructuredGraph graph, MetaAccessProvider runtime) {
@@ -414,14 +419,17 @@
 
         public final List<ResolvedJavaMethod> concretes;
         public final ArrayList<ProfiledType> ptypes;
-        public final int[] typesToConcretes;
+        public final ArrayList<Integer> typesToConcretes;
         public final double notRecordedTypeProbability;
+        private final ArrayList<Double> concretesProbabilities;
 
-        public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList<ResolvedJavaMethod> concretes, ArrayList<ProfiledType> ptypes, int[] typesToConcretes, double notRecordedTypeProbability) {
+        public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList<ResolvedJavaMethod> concretes, ArrayList<Double> concretesProbabilities, ArrayList<ProfiledType> ptypes,
+                        ArrayList<Integer> typesToConcretes, double notRecordedTypeProbability) {
             super(invoke);
-            assert concretes.size() > 0 && concretes.size() <= ptypes.size() : "must have at least one method but no more than types methods";
-            assert ptypes.size() == typesToConcretes.length : "array lengths must match";
+            assert concretes.size() > 0 : "must have at least one method";
+            assert ptypes.size() == typesToConcretes.size() : "array lengths must match";
 
+            this.concretesProbabilities = concretesProbabilities;
             this.concretes = concretes;
             this.ptypes = ptypes;
             this.typesToConcretes = typesToConcretes;
@@ -444,9 +452,9 @@
             // receiver null check must be the first node
             InliningUtil.receiverNullCheck(invoke);
             if (hasSingleMethod()) {
-                inlineSingleMethod(graph, callback, replacements, assumptions);
+                inlineSingleMethod(graph, callback, replacements, assumptions, runtime);
             } else {
-                inlineMultipleMethods(graph, callback, replacements, assumptions);
+                inlineMultipleMethods(graph, callback, replacements, assumptions, runtime);
             }
         }
 
@@ -458,7 +466,7 @@
             return notRecordedTypeProbability > 0;
         }
 
-        private void inlineMultipleMethods(StructuredGraph graph, InliningCallback callback, Replacements replacements, Assumptions assumptions) {
+        private void inlineMultipleMethods(StructuredGraph graph, InliningCallback callback, Replacements replacements, Assumptions assumptions, MetaAccessProvider runtime) {
             int numberOfMethods = concretes.size();
             FixedNode continuation = invoke.next();
 
@@ -513,7 +521,7 @@
             assert invoke.asNode().isAlive();
 
             // replace the invoke with a switch on the type of the actual receiver
-            createDispatchOnTypeBeforeInvoke(graph, successors, false);
+            boolean methodDispatch = createDispatchOnTypeBeforeInvoke(graph, successors, false, runtime);
 
             assert invoke.next() == continuation;
             invoke.setNext(null);
@@ -528,9 +536,15 @@
                 BeginNode node = successors[i];
                 Invoke invokeForInlining = (Invoke) node.next();
 
-                ResolvedJavaType commonType = getLeastCommonType(i);
+                ResolvedJavaType commonType;
+                if (methodDispatch) {
+                    commonType = concretes.get(i).getDeclaringClass();
+                } else {
+                    commonType = getLeastCommonType(i);
+                }
+
                 ValueNode receiver = ((MethodCallTargetNode) invokeForInlining.callTarget()).receiver();
-                boolean exact = getTypeCount(i) == 1;
+                boolean exact = (getTypeCount(i) == 1 && !methodDispatch);
                 PiNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact);
                 invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
 
@@ -541,6 +555,7 @@
             if (shouldFallbackToInvoke()) {
                 replacementNodes.add(null);
             }
+
             if (GraalOptions.OptTailDuplication) {
                 /*
                  * We might want to perform tail duplication at the merge after a type switch, if
@@ -560,15 +575,15 @@
                 if (opportunities > 0) {
                     metricInliningTailDuplication.increment();
                     Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities);
-                    TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes);
+                    TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, new HighTierContext(runtime, assumptions, replacements));
                 }
             }
         }
 
         private int getTypeCount(int concreteMethodIndex) {
             int count = 0;
-            for (int i = 0; i < typesToConcretes.length; i++) {
-                if (typesToConcretes[i] == concreteMethodIndex) {
+            for (int i = 0; i < typesToConcretes.size(); i++) {
+                if (typesToConcretes.get(i) == concreteMethodIndex) {
                     count++;
                 }
             }
@@ -577,8 +592,8 @@
 
         private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) {
             ResolvedJavaType commonType = null;
-            for (int i = 0; i < typesToConcretes.length; i++) {
-                if (typesToConcretes[i] == concreteMethodIndex) {
+            for (int i = 0; i < typesToConcretes.size(); i++) {
+                if (typesToConcretes.get(i) == concreteMethodIndex) {
                     if (commonType == null) {
                         commonType = ptypes.get(i).getType();
                     } else {
@@ -598,14 +613,14 @@
             return result;
         }
 
-        private void inlineSingleMethod(StructuredGraph graph, InliningCallback callback, Replacements replacements, Assumptions assumptions) {
+        private void inlineSingleMethod(StructuredGraph graph, InliningCallback callback, Replacements replacements, Assumptions assumptions, MetaAccessProvider runtime) {
             assert concretes.size() == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
 
             BeginNode calleeEntryNode = graph.add(new BeginNode());
 
             BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
             BeginNode[] successors = new BeginNode[]{calleeEntryNode, unknownTypeSux};
-            createDispatchOnTypeBeforeInvoke(graph, successors, false);
+            createDispatchOnTypeBeforeInvoke(graph, successors, false, runtime);
 
             calleeEntryNode.setNext(invoke.asNode());
 
@@ -613,20 +628,57 @@
             inline(invoke, concrete, callback, replacements, assumptions, false);
         }
 
-        private void createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor) {
-            assert ptypes.size() > 1;
+        private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor, MetaAccessProvider runtime) {
+            assert ptypes.size() >= 1;
 
             Kind hubKind = ((MethodCallTargetNode) invoke.callTarget()).targetMethod().getDeclaringClass().getEncoding(Representation.ObjectHub).getKind();
             LoadHubNode hub = graph.add(new LoadHubNode(((MethodCallTargetNode) invoke.callTarget()).receiver(), hubKind));
             graph.addBeforeFixed(invoke.asNode(), hub);
 
+            if (!invokeIsOnlySuccessor && chooseMethodDispatch()) {
+                assert successors.length == concretes.size() + 1;
+                assert concretes.size() > 0;
+                Debug.log("Method check cascade with %d methods", concretes.size());
+
+                LoadMethodNode[] methods = new LoadMethodNode[concretes.size()];
+                ValueNode[] constantMethods = new ValueNode[concretes.size()];
+                double[] probability = new double[concretes.size()];
+                for (int i = 0; i < concretes.size(); ++i) {
+                    ResolvedJavaMethod firstMethod = concretes.get(i);
+                    Constant firstMethodConstant = firstMethod.getEncoding();
+
+                    ValueNode firstMethodConstantNode = ConstantNode.forConstant(firstMethodConstant, runtime, graph);
+                    constantMethods[i] = firstMethodConstantNode;
+                    probability[i] = concretesProbabilities.get(i);
+                    if (i > 0) {
+                        probability[i] /= (1.0 - probability[i - 1]);
+                    }
+                }
+
+                FixedNode lastSucc = successors[concretes.size()];
+                for (int i = concretes.size() - 1; i >= 0; --i) {
+                    LoadMethodNode method = graph.add(new LoadMethodNode(concretes.get(i), hub, constantMethods[i].kind()));
+                    methods[i] = method;
+                    CompareNode methodCheck = CompareNode.createCompareNode(Condition.EQ, methods[i], constantMethods[i]);
+                    IfNode ifNode = graph.add(new IfNode(methodCheck, successors[i], lastSucc, probability[i]));
+                    method.setNext(ifNode);
+                    lastSucc = method;
+                }
+
+                FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
+                pred.setNext(lastSucc);
+                return true;
+            } else {
+                Debug.log("Type switch with %d types", concretes.size());
+            }
+
             ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.size()];
             double[] keyProbabilities = new double[ptypes.size() + 1];
             int[] keySuccessors = new int[ptypes.size() + 1];
             for (int i = 0; i < ptypes.size(); i++) {
                 keys[i] = ptypes.get(i).getType();
                 keyProbabilities[i] = ptypes.get(i).getProbability();
-                keySuccessors[i] = invokeIsOnlySuccessor ? 0 : typesToConcretes[i];
+                keySuccessors[i] = invokeIsOnlySuccessor ? 0 : typesToConcretes.get(i);
                 assert keySuccessors[i] < successors.length - 1 : "last successor is the unknownTypeSux";
             }
             keyProbabilities[keyProbabilities.length - 1] = notRecordedTypeProbability;
@@ -635,6 +687,45 @@
             TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(hub, successors, keys, keyProbabilities, keySuccessors));
             FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
             pred.setNext(typeSwitch);
+            return false;
+        }
+
+        private boolean chooseMethodDispatch() {
+            if (concretes.size() == 1 && this.notRecordedTypeProbability > 0) {
+                // Always chose method dispatch if there is a single concrete method and the call
+                // site is megamorphic.
+                return true;
+            }
+
+            if (concretes.size() == ptypes.size()) {
+                // Always prefer types over methods if the number of types is smaller than the
+                // number of methods.
+                return false;
+            }
+
+            return chooseMethodDispatchCostBased();
+        }
+
+        private boolean chooseMethodDispatchCostBased() {
+            double remainder = 1.0 - this.notRecordedTypeProbability;
+            double costEstimateMethodDispatch = remainder;
+            for (int i = 0; i < concretes.size(); ++i) {
+                if (i != 0) {
+                    costEstimateMethodDispatch += remainder;
+                }
+                remainder -= concretesProbabilities.get(i);
+            }
+
+            double costEstimateTypeDispatch = 0.0;
+            remainder = 1.0;
+            for (int i = 0; i < ptypes.size(); ++i) {
+                if (i != 0) {
+                    costEstimateTypeDispatch += remainder;
+                }
+                remainder -= ptypes.get(i).getProbability();
+            }
+            costEstimateTypeDispatch += notRecordedTypeProbability;
+            return costEstimateMethodDispatch < costEstimateTypeDispatch;
         }
 
         private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, MergeNode exceptionMerge, PhiNode exceptionObjectPhi,
@@ -691,17 +782,17 @@
         @Override
         public void tryToDevirtualizeInvoke(StructuredGraph graph, MetaAccessProvider runtime, Assumptions assumptions) {
             if (hasSingleMethod()) {
-                tryToDevirtualizeSingleMethod(graph);
+                tryToDevirtualizeSingleMethod(graph, runtime);
             } else {
-                tryToDevirtualizeMultipleMethods(graph);
+                tryToDevirtualizeMultipleMethods(graph, runtime);
             }
         }
 
-        private void tryToDevirtualizeSingleMethod(StructuredGraph graph) {
-            devirtualizeWithTypeSwitch(graph, InvokeKind.Special, concretes.get(0));
+        private void tryToDevirtualizeSingleMethod(StructuredGraph graph, MetaAccessProvider runtime) {
+            devirtualizeWithTypeSwitch(graph, InvokeKind.Special, concretes.get(0), runtime);
         }
 
-        private void tryToDevirtualizeMultipleMethods(StructuredGraph graph) {
+        private void tryToDevirtualizeMultipleMethods(StructuredGraph graph, MetaAccessProvider runtime) {
             MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget();
             if (methodCallTarget.invokeKind() == InvokeKind.Interface) {
                 ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod();
@@ -712,25 +803,25 @@
                 if (!leastCommonType.isInterface() && targetMethod.getDeclaringClass().isAssignableFrom(leastCommonType)) {
                     ResolvedJavaMethod baseClassTargetMethod = leastCommonType.resolveMethod(targetMethod);
                     if (baseClassTargetMethod != null) {
-                        devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveMethod(targetMethod));
+                        devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveMethod(targetMethod), runtime);
                     }
                 }
             }
         }
 
-        private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target) {
+        private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target, MetaAccessProvider runtime) {
             InliningUtil.receiverNullCheck(invoke);
 
             BeginNode invocationEntry = graph.add(new BeginNode());
             BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
             BeginNode[] successors = new BeginNode[]{invocationEntry, unknownTypeSux};
-            createDispatchOnTypeBeforeInvoke(graph, successors, true);
+            createDispatchOnTypeBeforeInvoke(graph, successors, true, runtime);
 
             invocationEntry.setNext(invoke.asNode());
             ValueNode receiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
             PiNode anchoredReceiver = createAnchoredReceiver(graph, invocationEntry, target.getDeclaringClass(), receiver, false);
             invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver);
-            replaceInvokeCallTarget(graph, kind, target);
+            replaceInvokeCallTarget(invoke, graph, kind, target);
         }
 
         private static BeginNode createUnknownTypeSuccessor(StructuredGraph graph) {
@@ -775,15 +866,13 @@
         @Override
         public void inline(StructuredGraph graph, MetaAccessProvider runtime, Replacements replacements, InliningCallback callback, Assumptions assumptions) {
             assumptions.record(takenAssumption);
-            Debug.log("recording assumption: %s", takenAssumption);
-
             super.inline(graph, runtime, replacements, callback, assumptions);
         }
 
         @Override
         public void tryToDevirtualizeInvoke(StructuredGraph graph, MetaAccessProvider runtime, Assumptions assumptions) {
             assumptions.record(takenAssumption);
-            replaceInvokeCallTarget(graph, InvokeKind.Special, concrete);
+            replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete);
         }
 
         @Override
@@ -802,7 +891,6 @@
         if (!checkInvokeConditions(invoke)) {
             return null;
         }
-        ResolvedJavaMethod caller = getCaller(invoke);
         MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
         ResolvedJavaMethod targetMethod = callTarget.targetMethod();
 
@@ -845,7 +933,7 @@
         }
 
         // type check based inlining
-        return getTypeCheckedInlineInfo(replacements, invoke, caller, holder, targetMethod, optimisticOpts);
+        return getTypeCheckedInlineInfo(replacements, invoke, targetMethod, optimisticOpts);
     }
 
     private static InlineInfo getAssumptionInlineInfo(Replacements replacements, Invoke invoke, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod concrete, Assumption takenAssumption) {
@@ -864,27 +952,28 @@
         return new ExactInlineInfo(invoke, targetMethod);
     }
 
-    private static InlineInfo getTypeCheckedInlineInfo(Replacements replacements, Invoke invoke, ResolvedJavaMethod caller, ResolvedJavaType holder, ResolvedJavaMethod targetMethod,
-                    OptimisticOptimizations optimisticOpts) {
-        ProfilingInfo profilingInfo = caller.getProfilingInfo();
-        JavaTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci());
-        if (typeProfile == null) {
+    private static InlineInfo getTypeCheckedInlineInfo(Replacements replacements, Invoke invoke, ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts) {
+        JavaTypeProfile typeProfile = null;
+        ValueNode receiver = invoke.callTarget().arguments().get(0);
+        if (receiver instanceof TypeProfileProxyNode) {
+            TypeProfileProxyNode typeProfileProxyNode = (TypeProfileProxyNode) receiver;
+            typeProfile = typeProfileProxyNode.getProfile();
+        } else {
             return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no type profile exists");
         }
 
-        ProfiledType[] rawProfiledTypes = typeProfile.getTypes();
-        ArrayList<ProfiledType> ptypes = getCompatibleTypes(rawProfiledTypes, holder);
-        if (ptypes == null || ptypes.size() <= 0) {
-            return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types remained after filtering (%d types were recorded)", rawProfiledTypes.length);
+        ProfiledType[] ptypes = typeProfile.getTypes();
+        if (ptypes == null || ptypes.length <= 0) {
+            return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types in profile");
         }
 
         double notRecordedTypeProbability = typeProfile.getNotRecordedProbability();
-        if (ptypes.size() == 1 && notRecordedTypeProbability == 0) {
+        if (ptypes.length == 1 && notRecordedTypeProbability == 0) {
             if (!optimisticOpts.inlineMonomorphicCalls()) {
                 return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining monomorphic calls is disabled");
             }
 
-            ResolvedJavaType type = ptypes.get(0).getType();
+            ResolvedJavaType type = ptypes[0].getType();
             ResolvedJavaMethod concrete = type.resolveMethod(targetMethod);
             if (!checkTargetConditions(replacements, invoke, concrete, optimisticOpts)) {
                 return null;
@@ -894,27 +983,68 @@
             invoke.setPolymorphic(true);
 
             if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) {
-                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.size());
+                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length);
             }
             if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) {
                 // due to filtering impossible types, notRecordedTypeProbability can be > 0 although
                 // the number of types is lower than what can be recorded in a type profile
-                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.size(),
+                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length,
                                 notRecordedTypeProbability * 100);
             }
 
-            // determine concrete methods and map type to specific method
+            // Find unique methods and their probabilities.
             ArrayList<ResolvedJavaMethod> concreteMethods = new ArrayList<>();
-            int[] typesToConcretes = new int[ptypes.size()];
-            for (int i = 0; i < ptypes.size(); i++) {
-                ResolvedJavaMethod concrete = ptypes.get(i).getType().resolveMethod(targetMethod);
-
+            ArrayList<Double> concreteMethodsProbabilities = new ArrayList<>();
+            for (int i = 0; i < ptypes.length; i++) {
+                ResolvedJavaMethod concrete = ptypes[i].getType().resolveMethod(targetMethod);
                 int index = concreteMethods.indexOf(concrete);
+                double curProbability = ptypes[i].getProbability();
                 if (index < 0) {
                     index = concreteMethods.size();
                     concreteMethods.add(concrete);
+                    concreteMethodsProbabilities.add(curProbability);
+                } else {
+                    concreteMethodsProbabilities.set(index, concreteMethodsProbabilities.get(index) + curProbability);
                 }
-                typesToConcretes[i] = index;
+            }
+
+            // Clear methods that fall below the threshold.
+            if (notRecordedTypeProbability > 0) {
+                ArrayList<ResolvedJavaMethod> newConcreteMethods = new ArrayList<>();
+                ArrayList<Double> newConcreteMethodsProbabilities = new ArrayList<>();
+                for (int i = 0; i < concreteMethods.size(); ++i) {
+                    if (concreteMethodsProbabilities.get(i) >= GraalOptions.MegamorphicInliningMinMethodProbability) {
+                        newConcreteMethods.add(concreteMethods.get(i));
+                        newConcreteMethodsProbabilities.add(concreteMethodsProbabilities.get(i));
+                    }
+                }
+
+                if (newConcreteMethods.size() == 0) {
+                    // No method left that is worth inlining.
+                    return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)", concreteMethods.size());
+                }
+
+                concreteMethods = newConcreteMethods;
+                concreteMethodsProbabilities = newConcreteMethodsProbabilities;
+            }
+
+            // Clean out types whose methods are no longer available.
+            ArrayList<ProfiledType> usedTypes = new ArrayList<>();
+            ArrayList<Integer> typesToConcretes = new ArrayList<>();
+            for (ProfiledType type : ptypes) {
+                ResolvedJavaMethod concrete = type.getType().resolveMethod(targetMethod);
+                int index = concreteMethods.indexOf(concrete);
+                if (index == -1) {
+                    notRecordedTypeProbability += type.getProbability();
+                } else {
+                    usedTypes.add(type);
+                    typesToConcretes.add(index);
+                }
+            }
+
+            if (usedTypes.size() == 0) {
+                // No type left that is worth checking for.
+                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length);
             }
 
             for (ResolvedJavaMethod concrete : concreteMethods) {
@@ -922,27 +1052,10 @@
                     return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined");
                 }
             }
-            return new MultiTypeGuardInlineInfo(invoke, concreteMethods, ptypes, typesToConcretes, notRecordedTypeProbability);
+            return new MultiTypeGuardInlineInfo(invoke, concreteMethods, concreteMethodsProbabilities, usedTypes, typesToConcretes, notRecordedTypeProbability);
         }
     }
 
-    private static ArrayList<ProfiledType> getCompatibleTypes(ProfiledType[] types, ResolvedJavaType holder) {
-        ArrayList<ProfiledType> result = new ArrayList<>();
-        for (int i = 0; i < types.length; i++) {
-            ProfiledType ptype = types[i];
-            ResolvedJavaType type = ptype.getType();
-            assert !type.isInterface() && (type.isArray() || !Modifier.isAbstract(type.getModifiers())) : type;
-            if (!GraalOptions.OptFilterProfiledTypes || holder.isAssignableFrom(type)) {
-                result.add(ptype);
-            }
-        }
-        return result;
-    }
-
-    private static ResolvedJavaMethod getCaller(Invoke invoke) {
-        return invoke.stateAfter().method();
-    }
-
     private static PiNode createAnchoredReceiver(StructuredGraph graph, FixedNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) {
         // to avoid that floating reads on receiver fields float above the type check
         return graph.unique(new PiNode(receiver, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType), anchor));
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Sun Apr 28 22:52:12 2013 +0200
@@ -24,7 +24,7 @@
 
 import java.util.*;
 
-import com.oracle.graal.graph.Graph.InputChangedListener;
+import com.oracle.graal.graph.Graph.NodeChangedListener;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
@@ -49,7 +49,7 @@
         }
     }
 
-    private static class Listener implements InputChangedListener {
+    private static class Listener implements NodeChangedListener {
 
         private final Set<Node> canonicalizationRoots;
 
@@ -58,7 +58,7 @@
         }
 
         @Override
-        public void inputChanged(Node node) {
+        public void nodeChanged(Node node) {
             canonicalizationRoots.add(node);
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Sun Apr 28 22:52:12 2013 +0200
@@ -68,8 +68,14 @@
         }
 
         @Override
-        public ValueNode createNullCheckGuard(ValueNode object) {
-            return createGuard(object.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true);
+        public ValueNode createNullCheckGuard(NodeInputList<ValueNode> list, ValueNode object) {
+            if (object.objectStamp().nonNull()) {
+                // Short cut creation of null check guard if the object is known to be non-null.
+                return null;
+            }
+            ValueNode guard = createGuard(object.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true);
+            list.add(guard);
+            return guard;
         }
 
         @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Sun Apr 28 22:52:12 2013 +0200
@@ -36,13 +36,14 @@
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
+import com.oracle.graal.phases.tiers.*;
 
 /**
  * This class is a phase that looks for opportunities for tail duplication. The static method
- * {@link #tailDuplicate(MergeNode, TailDuplicationDecision, List)} can also be used to drive tail
- * duplication from other places, e.g., inlining.
+ * {@link #tailDuplicate(MergeNode, TailDuplicationDecision, List, PhaseContext)} can also be used
+ * to drive tail duplication from other places, e.g., inlining.
  */
-public class TailDuplicationPhase extends Phase {
+public class TailDuplicationPhase extends BasePhase<PhaseContext> {
 
     /*
      * Various metrics on the circumstances in which tail duplication was/wasn't performed.
@@ -129,14 +130,14 @@
     };
 
     @Override
-    protected void run(StructuredGraph graph) {
+    protected void run(StructuredGraph graph, PhaseContext phaseContext) {
         NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
 
         // A snapshot is taken here, so that new MergeNode instances aren't considered for tail
         // duplication.
         for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) {
             if (!(merge instanceof LoopBeginNode) && nodeProbabilities.get(merge) >= GraalOptions.TailDuplicationProbability) {
-                tailDuplicate(merge, DEFAULT_DECISION, null);
+                tailDuplicate(merge, DEFAULT_DECISION, null, phaseContext);
             }
         }
     }
@@ -156,8 +157,9 @@
      *            size needs to match the merge's end count. Each entry can either be null or a
      *            {@link PiNode}, and is used to replace {@link PiNode#object()} with the
      *            {@link PiNode} in the duplicated branch that corresponds to the entry.
+     * @param phaseContext
      */
-    public static boolean tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List<PiNode> replacements) {
+    public static boolean tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List<PiNode> replacements, PhaseContext phaseContext) {
         assert !(merge instanceof LoopBeginNode);
         assert replacements == null || replacements.size() == merge.forwardEndCount();
         FixedNode fixed = merge;
@@ -171,14 +173,14 @@
                 metricDuplicationEnd.increment();
                 if (decision.doTransform(merge, fixedCount)) {
                     metricDuplicationEndPerformed.increment();
-                    new DuplicationOperation(merge, replacements).duplicate();
+                    new DuplicationOperation(merge, replacements).duplicate(phaseContext);
                     return true;
                 }
             } else if (merge.stateAfter() != null) {
                 metricDuplicationOther.increment();
                 if (decision.doTransform(merge, fixedCount)) {
                     metricDuplicationOtherPerformed.increment();
-                    new DuplicationOperation(merge, replacements).duplicate();
+                    new DuplicationOperation(merge, replacements).duplicate(phaseContext);
                     return true;
                 }
             }
@@ -220,10 +222,14 @@
          * <li>Determines the complete set of duplicated nodes.</li>
          * <li>Performs the actual duplication.</li>
          * </ul>
+         * 
+         * @param phaseContext
          */
-        private void duplicate() {
+        private void duplicate(PhaseContext phaseContext) {
             Debug.log("tail duplication at merge %s in %s", merge, graph.method());
 
+            int startMark = graph.getMark();
+
             ValueAnchorNode anchor = addValueAnchor();
 
             // determine the fixed nodes that should be duplicated (currently: all nodes up until
@@ -297,6 +303,7 @@
                     phi.setMerge(mergeAfter);
                 }
             }
+            new CanonicalizerPhase(null, graph.getNewNodes(startMark)).apply(graph, phaseContext);
             Debug.dump(graph, "After tail duplication at %s", merge);
         }
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Sun Apr 28 22:52:12 2013 +0200
@@ -44,7 +44,8 @@
     public static boolean Intrinsify                         = true;
            static boolean InlineMonomorphicCalls             = true;
            static boolean InlinePolymorphicCalls             = true;
-           static boolean InlineMegamorphicCalls             = ____;
+           static boolean InlineMegamorphicCalls             = true;
+    public static double  MegamorphicInliningMinMethodProbability = 0.33;
     public static int     MaximumDesiredSize                 = 5000;
     public static int     MaximumRecursiveInlining           = 1;
     public static float   BoostInliningForEscapeAnalysis     = 2f;
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Sun Apr 28 22:52:12 2013 +0200
@@ -446,9 +446,10 @@
                 @Override
                 protected void doState(LIRFrameState state) {
                     if (state.hasDebugInfo()) {
-                        stateString.append(debugInfoToString(state.debugInfo().getBytecodePosition(), state.debugInfo().getRegisterRefMap(), state.debugInfo().getFrameRefMap(), target.arch));
+                        DebugInfo di = state.debugInfo();
+                        stateString.append(debugInfoToString(di.getBytecodePosition(), di.getRegisterRefMap(), di.getFrameRefMap(), di.getCalleeSaveInfo(), target.arch));
                     } else {
-                        stateString.append(debugInfoToString(state.topFrame, null, null, target.arch));
+                        stateString.append(debugInfoToString(state.topFrame, null, null, null, target.arch));
                     }
                 }
             });
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CompilationPrinter.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CompilationPrinter.java	Sun Apr 28 22:52:12 2013 +0200
@@ -114,7 +114,7 @@
     /**
      * Formats given debug info as a multi line string.
      */
-    protected String debugInfoToString(BytecodePosition codePos, BitSet registerRefMap, BitSet frameRefMap, Architecture arch) {
+    protected String debugInfoToString(BytecodePosition codePos, BitSet registerRefMap, BitSet frameRefMap, RegisterSaveLayout calleeSaveInfo, Architecture arch) {
         StringBuilder sb = new StringBuilder();
 
         if (registerRefMap != null) {
@@ -128,8 +128,16 @@
 
         if (frameRefMap != null) {
             sb.append("frame-ref-map:");
-            for (int reg = frameRefMap.nextSetBit(0); reg >= 0; reg = frameRefMap.nextSetBit(reg + 1)) {
-                sb.append(' ').append("s").append(reg);
+            for (int slot = frameRefMap.nextSetBit(0); slot >= 0; slot = frameRefMap.nextSetBit(slot + 1)) {
+                sb.append(' ').append("s").append(slot);
+            }
+            sb.append("\n");
+        }
+
+        if (calleeSaveInfo != null) {
+            sb.append("callee-save-info:");
+            for (Map.Entry<Register, Integer> e : calleeSaveInfo.registersToSlots(true).entrySet()) {
+                sb.append(" " + e.getKey() + " -> s" + e.getValue());
             }
             sb.append("\n");
         }
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java	Sun Apr 28 22:52:12 2013 +0200
@@ -57,8 +57,7 @@
      */
     @Snippet
     public static int f2i(float input, int result) {
-        if (result == Integer.MIN_VALUE) {
-            probability(NOT_FREQUENT_PROBABILITY);
+        if (probability(SLOW_PATH_PROBABILITY, result == Integer.MIN_VALUE)) {
             if (Float.isNaN(input)) {
                 // input is NaN -> return 0
                 return 0;
@@ -83,8 +82,7 @@
      */
     @Snippet
     public static long f2l(float input, long result) {
-        if (result == Long.MIN_VALUE) {
-            probability(NOT_FREQUENT_PROBABILITY);
+        if (probability(SLOW_PATH_PROBABILITY, result == Long.MIN_VALUE)) {
             if (Float.isNaN(input)) {
                 // input is NaN -> return 0
                 return 0;
@@ -109,8 +107,7 @@
      */
     @Snippet
     public static int d2i(double input, int result) {
-        if (result == Integer.MIN_VALUE) {
-            probability(NOT_FREQUENT_PROBABILITY);
+        if (probability(SLOW_PATH_PROBABILITY, result == Integer.MIN_VALUE)) {
             if (Double.isNaN(input)) {
                 // input is NaN -> return 0
                 return 0;
@@ -135,8 +132,7 @@
      */
     @Snippet
     public static long d2l(double input, long result) {
-        if (result == Long.MIN_VALUE) {
-            probability(NOT_FREQUENT_PROBABILITY);
+        if (probability(SLOW_PATH_PROBABILITY, result == Long.MIN_VALUE)) {
             if (Double.isNaN(input)) {
                 // input is NaN -> return 0
                 return 0;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Sun Apr 28 22:52:12 2013 +0200
@@ -97,8 +97,8 @@
      */
     protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, LoweringTool tool, int nUsages, Instantiation instantiation, Node usage, final StructuredGraph graph) {
         InstanceOfUsageReplacer replacer;
-        if (usage instanceof IfNode) {
-            replacer = new IfUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, (IfNode) usage);
+        if (usage instanceof IfNode || usage instanceof FixedGuardNode) {
+            replacer = new IfUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, (FixedNode) usage);
         } else {
             assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage;
             ConditionalNode c = (ConditionalNode) usage;
@@ -193,9 +193,9 @@
      */
     public static class IfUsageReplacer extends InstanceOfUsageReplacer {
 
-        private final IfNode usage;
+        private final FixedNode usage;
 
-        public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, IfNode usage) {
+        public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, FixedNode usage) {
             super(instantiation, instanceOf, trueValue, falseValue);
             this.usage = usage;
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.replacements;
 
+import static com.oracle.graal.api.meta.MetaUtil.*;
+
 import java.lang.reflect.*;
 import java.util.*;
 
@@ -178,7 +180,8 @@
         } else {
             result = runtime.lookupJavaType(intrinsic.value());
         }
-        assert runtime.lookupJavaType(ValueNode.class).isAssignableFrom(result);
+        assert runtime.lookupJavaType(ValueNode.class).isAssignableFrom(result) : "Node intrinsic class " + toJavaName(result, false) + " derived from @" + NodeIntrinsic.class.getSimpleName() +
+                        " annotation on " + format("%H.%n(%p)", target) + " is not a subclass of " + ValueNode.class;
         return result;
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java	Sun Apr 28 22:52:12 2013 +0200
@@ -24,20 +24,20 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.replacements.Snippet.*;
+import com.oracle.graal.replacements.Snippet.Fold;
 
 /**
  * Checks that a graph contains no calls to {@link NodeIntrinsic} or {@link Fold} methods.
  */
 public class NodeIntrinsificationVerificationPhase extends Phase {
 
-    public static boolean verify(StructuredGraph graph) {
+    public static void verify(StructuredGraph graph) {
         new NodeIntrinsificationVerificationPhase().apply(graph);
-        return true;
     }
 
     @Override
@@ -49,11 +49,17 @@
 
     private static void checkInvoke(MethodCallTargetNode n) {
         ResolvedJavaMethod target = n.targetMethod();
-        NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class);
-        if (intrinsic != null) {
-            throw new GraalInternalError("Illegal call to node intrinsic in " + n.graph() + ": " + n.invoke());
+        if (target.getAnnotation(Node.NodeIntrinsic.class) != null) {
+            error(n, "Intrinsification");
         } else if (target.getAnnotation(Fold.class) != null) {
-            throw new GraalInternalError("Illegal call to foldable method in " + n.graph() + ": " + n.invoke());
+            error(n, "Folding");
         }
     }
+
+    private static void error(MethodCallTargetNode n, String failedAction) throws GraalInternalError {
+        String context = MetaUtil.format("%H.%n", ((StructuredGraph) n.graph()).method());
+        String target = n.invoke().callTarget().targetName();
+        throw new GraalInternalError(failedAction + " of call to '" + target + "' in '" + context + "' failed, most likely due to a parameter annotated with @" +
+                        ConstantNodeParameter.class.getSimpleName() + " not being resolvable to a constant during compilation");
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Sun Apr 28 22:52:12 2013 +0200
@@ -279,7 +279,10 @@
          */
         protected void finalizeGraph(StructuredGraph graph) {
             new NodeIntrinsificationPhase(runtime).apply(graph);
-            assert SnippetTemplate.hasConstantParameter(method) || NodeIntrinsificationVerificationPhase.verify(graph);
+            if (!SnippetTemplate.hasConstantParameter(method)) {
+                NodeIntrinsificationVerificationPhase.verify(graph);
+            }
+            new ConvertDeoptimizeToGuardPhase().apply(graph);
 
             if (original == null) {
                 new SnippetFrameStateCleanupPhase().apply(graph);
@@ -293,7 +296,14 @@
         private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy) {
             StructuredGraph graph = graphCache.get(methodToParse);
             if (graph == null) {
-                graphCache.putIfAbsent(methodToParse, buildGraph(methodToParse, policy == null ? inliningPolicy(methodToParse) : policy));
+                StructuredGraph newGraph = Debug.scope("ParseGraph", new Object[]{methodToParse}, new Callable<StructuredGraph>() {
+
+                    public StructuredGraph call() throws Exception {
+                        return buildGraph(methodToParse, policy == null ? inliningPolicy(methodToParse) : policy);
+                    }
+                });
+
+                graphCache.putIfAbsent(methodToParse, newGraph);
                 graph = graphCache.get(methodToParse);
                 assert graph != null;
             }
@@ -309,8 +319,6 @@
             GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE);
             graphBuilder.apply(graph);
 
-            Debug.dump(graph, "%s: %s", methodToParse.getName(), GraphBuilderPhase.class.getSimpleName());
-
             new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph);
 
             return graph;
@@ -364,6 +372,11 @@
                         if (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)) {
                             targetGraph = intrinsicGraph;
                         } else {
+                            if (callee.getName().startsWith("$jacoco")) {
+                                throw new GraalInternalError("Parsing call to JaCoCo instrumentation method " + format("%H.%n(%p)", callee) + " from " + format("%H.%n(%p)", methodToParse) +
+                                                " while preparing replacement " + format("%H.%n(%p)", method) + ". Placing \"//JaCoCo Exclude\" anywhere in " +
+                                                methodToParse.getDeclaringClass().getSourceFileName() + " should fix this.");
+                            }
                             targetGraph = parseGraph(callee, policy);
                         }
                         InliningUtil.inline(callTarget.invoke(), targetGraph, true);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Sun Apr 28 22:52:12 2013 +0200
@@ -378,7 +378,7 @@
 
             new CanonicalizerPhase.Instance(runtime, replacements.getAssumptions(), 0, null).apply(snippetCopy);
         }
-        assert NodeIntrinsificationVerificationPhase.verify(snippetCopy);
+        NodeIntrinsificationVerificationPhase.verify(snippetCopy);
 
         // Gather the template parameters
         parameters = new Object[parameterCount];
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BranchProbabilityNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BranchProbabilityNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,17 +22,17 @@
  */
 package com.oracle.graal.replacements.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
 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 {
+public class BranchProbabilityNode extends FloatingNode implements Canonicalizable, Lowerable {
 
     public static final double LIKELY_PROBABILITY = 0.6;
     public static final double NOT_LIKELY_PROBABILITY = 1 - LIKELY_PROBABILITY;
@@ -43,41 +43,80 @@
     public static final double FAST_PATH_PROBABILITY = 0.99;
     public static final double SLOW_PATH_PROBABILITY = 1 - FAST_PATH_PROBABILITY;
 
-    public static final double NOT_DEOPT_PATH_PROBABILITY = 0.999;
-    public static final double DEOPT_PATH_PROBABILITY = 1 - NOT_DEOPT_PATH_PROBABILITY;
+    public static final double VERY_FAST_DEOPT_PATH_PROBABILITY = 0.999;
+    public static final double VERY_SLOW_PATH_PROBABILITY = 1 - VERY_FAST_DEOPT_PATH_PROBABILITY;
 
-    private final double probability;
+    @Input private ValueNode probability;
+    @Input private ValueNode condition;
 
-    public BranchProbabilityNode(double probability) {
-        super(StampFactory.forVoid());
-        assert probability >= 0 && probability <= 1;
+    public BranchProbabilityNode(ValueNode probability, ValueNode condition) {
+        super(condition.stamp());
         this.probability = probability;
+        this.condition = condition;
+    }
+
+    public ValueNode getProbability() {
+        return probability;
+    }
+
+    public ValueNode getCondition() {
+        return condition;
     }
 
     @Override
-    public void simplify(SimplifierTool tool) {
-        FixedNode current = this;
-        while (!(current instanceof BeginNode)) {
-            current = (FixedNode) current.predecessor();
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (probability.isConstant()) {
+            double probabilityValue = probability.asConstant().asDouble();
+            if (probabilityValue < 0.0) {
+                throw new GraalInternalError("A negative probability of " + probabilityValue + " is not allowed!");
+            } else if (probabilityValue > 1.0) {
+                throw new GraalInternalError("A probability of more than 1.0 (" + probabilityValue + ") is not allowed!");
+            }
+            boolean couldSet = false;
+            for (IntegerEqualsNode node : this.usages().filter(IntegerEqualsNode.class)) {
+                if (node.condition() == Condition.EQ) {
+                    ValueNode other = node.x();
+                    if (node.x() == this) {
+                        other = node.y();
+                    }
+                    if (other.isConstant()) {
+                        double probabilityToSet = probabilityValue;
+                        if (other.asConstant().asInt() == 0) {
+                            probabilityToSet = 1.0 - probabilityToSet;
+                        }
+                        for (IfNode ifNodeUsages : node.usages().filter(IfNode.class)) {
+                            couldSet = true;
+                            ifNodeUsages.setTrueSuccessorProbability(probabilityToSet);
+                        }
+                    }
+                }
+            }
+            if (!couldSet) {
+                throw new GraalInternalError("Wrong usage of branch probability injection!");
+            }
+            return condition;
         }
-        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.setTrueSuccessorProbability(probability);
-        } else {
-            ifNode.setTrueSuccessorProbability(1 - probability);
-        }
-
-        FixedNode next = next();
-        setNext(null);
-        ((FixedWithNextNode) predecessor()).setNext(next);
-        GraphUtil.killCFG(this);
+        return this;
     }
 
-    @SuppressWarnings("unused")
+    /**
+     * This intrinsic should only be used for the condition of an if statement. The parameter
+     * condition should also only denote a simple condition and not a combined condition involving
+     * && or || operators. It injects the probability of the condition into the if statement.
+     * 
+     * @param probability the probability that the given condition is true as a double value between
+     *            0.0 and 1.0.
+     * @param condition the simple condition without any && or || operators
+     * @return the condition
+     */
     @NodeIntrinsic
-    public static void probability(@ConstantNodeParameter double probability) {
+    public static boolean probability(double probability, boolean condition) {
+        assert probability >= 0.0 && probability <= 1.0;
+        return condition;
     }
 
+    @Override
+    public void lower(LoweringTool tool, LoweringType loweringType) {
+        throw new GraalInternalError("Branch probability could not be injected, because the probability value did not reduce to a constant value.");
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -47,7 +47,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        gen.setResult(this, gen.emitLoad(readKind, gen.operand(address), 0, Value.ILLEGAL, 0, null));
+        gen.setResult(this, gen.emitLoad(readKind, gen.operand(address), null));
     }
 
     @SuppressWarnings("unchecked")
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -50,7 +50,7 @@
     @Override
     public void generate(LIRGeneratorTool gen) {
         Value v = gen.operand(value);
-        gen.emitStore(kind, gen.operand(address), 0, Value.ILLEGAL, 0, v, null);
+        gen.emitStore(kind, gen.operand(address), v, null);
     }
 
     /*
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -71,6 +71,7 @@
         StructuredGraph snippetGraph = getSnippetGraph(tool);
 
         InvokeNode invoke = replaceWithInvoke();
+        assert invoke.verify();
 
         if (snippetGraph != null) {
             InliningUtil.inline(invoke, snippetGraph, false);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java	Sun Apr 28 22:52:12 2013 +0200
@@ -54,7 +54,7 @@
     @Override
     public void generate(LIRGeneratorTool generator) {
         Value val = generator.operand(value);
-        generator.emitMove(val, register.asValue(val.getKind()));
+        generator.emitMove(register.asValue(val.getKind()), val);
     }
 
     @Override
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/AssumptionsTest.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/AssumptionsTest.java	Sun Apr 28 22:52:12 2013 +0200
@@ -38,7 +38,7 @@
     @Test
     public void testSingleAssumption() {
         Assumption assumption = Truffle.getRuntime().createAssumption();
-        TestRootNode<?> root = TestHelper.create(SingleAssumptionNodeFactory.getInstance(), assumption);
+        TestRootNode<?> root = TestHelper.createRoot(SingleAssumptionNodeFactory.getInstance(), assumption);
 
         Assert.assertEquals(42, TestHelper.executeWith(root));
         assumption.invalidate();
@@ -63,7 +63,7 @@
     public void testMultipleAssumption() {
         Assumption assumption1 = Truffle.getRuntime().createAssumption();
         Assumption assumption2 = Truffle.getRuntime().createAssumption();
-        TestRootNode<?> root = TestHelper.create(MultipleAssumptionsNodeFactory.getInstance(), assumption1, assumption2);
+        TestRootNode<?> root = TestHelper.createRoot(MultipleAssumptionsNodeFactory.getInstance(), assumption1, assumption2);
 
         Assert.assertEquals(42, TestHelper.executeWith(root));
         assumption2.invalidate();
@@ -95,7 +95,7 @@
     public void testDerivedAssumption() {
         Assumption additionalAssumption = Truffle.getRuntime().createAssumption();
         Assumption assumption = Truffle.getRuntime().createAssumption();
-        TestRootNode<?> root = TestHelper.create(DerivedAssumptionNodeFactory.getInstance(), assumption, additionalAssumption);
+        TestRootNode<?> root = TestHelper.createRoot(DerivedAssumptionNodeFactory.getInstance(), assumption, additionalAssumption);
 
         Assert.assertEquals(42, TestHelper.executeWith(root));
         assumption.invalidate();
@@ -117,7 +117,7 @@
     public void testDerivedAssumptionRedeclared() {
         Assumption additionalAssumption = Truffle.getRuntime().createAssumption();
         Assumption assumption = Truffle.getRuntime().createAssumption();
-        TestRootNode<?> root = TestHelper.create(DerivedAssumptionRedeclaredNodeFactory.getInstance(), additionalAssumption, assumption);
+        TestRootNode<?> root = TestHelper.createRoot(DerivedAssumptionRedeclaredNodeFactory.getInstance(), additionalAssumption, assumption);
 
         Assert.assertEquals(42, TestHelper.executeWith(root));
         assumption.invalidate();
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryNodeTest.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryNodeTest.java	Sun Apr 28 22:52:12 2013 +0200
@@ -36,7 +36,7 @@
 
     @Test
     public void testAdd() {
-        TestRootNode<AddNode> node = create(AddNodeFactory.getInstance());
+        TestRootNode<AddNode> node = createRoot(AddNodeFactory.getInstance());
         assertEquals(42, executeWith(node, 19, 23));
         assertEquals(42d, executeWith(node, 19d, 23d));
         assertEquals(42d, executeWith(node, "19", "23"));
@@ -45,7 +45,7 @@
 
     @Test(expected = RuntimeException.class)
     public void testAddUnsupported() {
-        TestRootNode<AddNode> node = create(AddNodeFactory.getInstance());
+        TestRootNode<AddNode> node = createRoot(AddNodeFactory.getInstance());
         executeWith(node, new Object(), new Object());
     }
 
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java	Sun Apr 28 22:52:12 2013 +0200
@@ -39,7 +39,7 @@
 
     @Test
     public void testConcat() {
-        TestRootNode<BuiltinNode> node = create(StrConcatFactory.getInstance(), new Context());
+        TestRootNode<BuiltinNode> node = createRoot(StrConcatFactory.getInstance(), new Context());
         Str str1 = new Str("42");
         Str str2 = new Str(" is the number.");
         assertEquals(str1.concat(str2), executeWith(node, str1, str2));
@@ -47,13 +47,13 @@
 
     @Test(expected = UnsupportedOperationException.class)
     public void testConcatUnsupported() {
-        TestRootNode<BuiltinNode> node = create(StrConcatFactory.getInstance(), new Context());
+        TestRootNode<BuiltinNode> node = createRoot(StrConcatFactory.getInstance(), new Context());
         executeWith(node, 42, new Str(" is the number."));
     }
 
     @Test
     public void testSubstrSpecialized() {
-        TestRootNode<BuiltinNode> node = create(StrSubstrFactory.getInstance(), new Context());
+        TestRootNode<BuiltinNode> node = createRoot(StrSubstrFactory.getInstance(), new Context());
         Str str = new Str("test 42");
 
         assertEquals(str.substr(5, 7), executeWith(node, str, 5, 7));
@@ -61,7 +61,7 @@
 
     @Test
     public void testSubstrGeneric() {
-        TestRootNode<BuiltinNode> node = create(StrSubstrFactory.getInstance(), new Context());
+        TestRootNode<BuiltinNode> node = createRoot(StrSubstrFactory.getInstance(), new Context());
         Str str = new Str("test 42");
 
         assertEquals(Str.substr(str, "5", "7"), executeWith(node, str, "5", "7"));
@@ -69,27 +69,27 @@
 
     @Test(expected = UnsupportedOperationException.class)
     public void testSubstrUnsupported() {
-        TestRootNode<BuiltinNode> node = create(StrSubstrFactory.getInstance(), new Context());
+        TestRootNode<BuiltinNode> node = createRoot(StrSubstrFactory.getInstance(), new Context());
         executeWith(node, new Object(), "5", "7");
     }
 
     @Test
     public void testLength() {
-        TestRootNode<BuiltinNode> node = create(StrLengthFactory.getInstance(), new Context());
+        TestRootNode<BuiltinNode> node = createRoot(StrLengthFactory.getInstance(), new Context());
         Str testStr = new Str("test 42");
         assertEquals(testStr.length(), executeWith(node, testStr));
     }
 
     @Test(expected = UnsupportedOperationException.class)
     public void testLengthUnsupported() {
-        TestRootNode<BuiltinNode> node = create(StrLengthFactory.getInstance(), new Context());
+        TestRootNode<BuiltinNode> node = createRoot(StrLengthFactory.getInstance(), new Context());
         executeWith(node, new Object());
     }
 
     @Test
     public void testAccessContext() {
         Context context = new Context();
-        TestRootNode<BuiltinNode> node = create(StrAccessContextFactory.getInstance(), context);
+        TestRootNode<BuiltinNode> node = createRoot(StrAccessContextFactory.getInstance(), context);
         // accessible by node
         assertSame(context, node.getNode().getContext());
         // accessible by execution
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/ExecuteEvaluatedTest.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/ExecuteEvaluatedTest.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,48 +22,86 @@
  */
 package com.oracle.truffle.api.codegen.test;
 
+import org.junit.*;
+
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.codegen.*;
+import com.oracle.truffle.api.codegen.test.ExecuteEvaluatedTestFactory.DoubleEvaluatedNodeFactory;
+import com.oracle.truffle.api.codegen.test.ExecuteEvaluatedTestFactory.EvaluatedNodeFactory;
+import com.oracle.truffle.api.codegen.test.ExecuteEvaluatedTestFactory.UseDoubleEvaluatedNodeFactory;
+import com.oracle.truffle.api.codegen.test.ExecuteEvaluatedTestFactory.UseEvaluatedNodeFactory;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.ArgumentNode;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestArguments;
 import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 
 public class ExecuteEvaluatedTest {
 
-    /* Represents target[element] */
-    @NodeChildren({@NodeChild("target"), @NodeChild("element")})
-    abstract static class ReadElementNode extends ValueNode {
+    @Test
+    public void testSingleEvaluated() {
+        ArgumentNode arg0 = new ArgumentNode(0);
+        CallTarget callTarget = TestHelper.createCallTarget(UseEvaluatedNodeFactory.create(arg0, EvaluatedNodeFactory.create(null)));
+
+        Assert.assertEquals(43, callTarget.call(new TestArguments(42)));
+        Assert.assertEquals(1, arg0.getInvocationCount());
+    }
+
+    @NodeChild("exp")
+    abstract static class EvaluatedNode extends ValueNode {
 
         @Specialization
-        int getInt(Object[] target, int element) {
-            return (int) target[element];
+        int doExecuteWith(int exp) {
+            return exp + 1;
         }
 
-        public abstract Object executeWith(VirtualFrame frame, Object targetValue);
+        public abstract Object executeEvaluated(VirtualFrame frame, Object targetValue);
+
+        public abstract int executeIntEvaluated(VirtualFrame frame, Object targetValue) throws UnexpectedResultException;
     }
 
-    /* Represents target[element]() */
-    @NodeChildren({@NodeChild("target"), @NodeChild(value = "element", type = ReadElementNode.class, executeWith = "target")})
-    abstract static class ElementCallNode extends ValueNode {
+    @NodeChildren({@NodeChild("exp0"), @NodeChild(value = "exp1", type = EvaluatedNode.class, executeWith = "exp0")})
+    abstract static class UseEvaluatedNode extends ValueNode {
 
         @Specialization
-        Object call(Object receiver, Object callTarget) {
-            return ((CallTarget) callTarget).call(new TestArguments(receiver));
+        int call(int exp0, int exp1) {
+            Assert.assertEquals(exp0 + 1, exp1);
+            return exp1;
         }
+    }
 
+    @Test
+    public void testDoubleEvaluated() {
+        ArgumentNode arg0 = new ArgumentNode(0);
+        ArgumentNode arg1 = new ArgumentNode(1);
+        CallTarget callTarget = TestHelper.createCallTarget(UseDoubleEvaluatedNodeFactory.create(arg0, arg1, DoubleEvaluatedNodeFactory.create(null, null)));
+
+        Assert.assertEquals(85, callTarget.call(new TestArguments(42, 43)));
+        Assert.assertEquals(1, arg0.getInvocationCount());
+        Assert.assertEquals(1, arg1.getInvocationCount());
     }
 
-    public static class TestArguments extends Arguments {
+    @NodeChildren({@NodeChild("exp0"), @NodeChild("exp1")})
+    abstract static class DoubleEvaluatedNode extends ValueNode {
 
-        private final Object receiver;
-
-        public TestArguments(Object receiver) {
-            this.receiver = receiver;
+        @Specialization
+        int doExecuteWith(int exp0, int exp1) {
+            return exp0 + exp1;
         }
 
-        public Object getReceiver() {
-            return receiver;
+        public abstract Object executeEvaluated(VirtualFrame frame, Object exp0, Object exp1);
+
+        public abstract int executeIntEvaluated(VirtualFrame frame, Object exp0, Object exp1) throws UnexpectedResultException;
+    }
+
+    @NodeChildren({@NodeChild("exp0"), @NodeChild("exp1"), @NodeChild(value = "exp2", type = DoubleEvaluatedNode.class, executeWith = {"exp0", "exp1"})})
+    abstract static class UseDoubleEvaluatedNode extends ValueNode {
+
+        @Specialization
+        int call(int exp0, int exp1, int exp2) {
+            Assert.assertEquals(exp0 + exp1, exp2);
+            return exp2;
         }
-
     }
 
 }
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java	Sun Apr 28 22:52:12 2013 +0200
@@ -40,7 +40,7 @@
 
     @Test
     public void testGuardInvocations() {
-        TestRootNode<InvocationGuard> root = create(InvocationGuardFactory.getInstance());
+        TestRootNode<InvocationGuard> root = createRoot(InvocationGuardFactory.getInstance());
 
         assertEquals(Integer.MAX_VALUE, executeWith(root, Integer.MAX_VALUE - 1, 1));
         assertEquals(1, InvocationGuard.specializedInvocations);
@@ -76,7 +76,7 @@
 
     @Test
     public void testGuardGlobal() {
-        TestRootNode<GlobalFlagGuard> root = create(GlobalFlagGuardFactory.getInstance());
+        TestRootNode<GlobalFlagGuard> root = createRoot(GlobalFlagGuardFactory.getInstance());
 
         assertEquals(42, executeWith(root, NULL));
 
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java	Sun Apr 28 22:52:12 2013 +0200
@@ -42,7 +42,7 @@
         return nodes;
     }
 
-    static <E extends ValueNode> TestRootNode<E> create(NodeFactory<E> factory, Object... constants) {
+    static <E extends ValueNode> E createNode(NodeFactory<E> factory, Object... constants) {
         ArgumentNode[] argumentNodes = arguments(factory.getExecutionSignature().size());
 
         List<Object> argumentList = new ArrayList<>();
@@ -52,11 +52,23 @@
         } else {
             argumentList.addAll(Arrays.asList(argumentNodes));
         }
-        return new TestRootNode<>(factory.createNode(argumentList.toArray(new Object[argumentList.size()])));
+        return factory.createNode(argumentList.toArray(new Object[argumentList.size()]));
+    }
+
+    static <E extends ValueNode> TestRootNode<E> createRoot(NodeFactory<E> factory, Object... constants) {
+        return new TestRootNode<>(createNode(factory, constants));
+    }
+
+    static CallTarget createCallTarget(ValueNode node) {
+        return createCallTarget(new TestRootNode<>(node));
+    }
+
+    static CallTarget createCallTarget(TestRootNode<? extends ValueNode> node) {
+        return Truffle.getRuntime().createCallTarget(node);
     }
 
     static <E> Object executeWith(TestRootNode<? extends ValueNode> node, Object... values) {
-        return Truffle.getRuntime().createCallTarget(node).call(new TestArguments(values));
+        return createCallTarget(node).call(new TestArguments(values));
     }
 
 }
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java	Sun Apr 28 22:52:12 2013 +0200
@@ -101,15 +101,21 @@
 
     public static class ArgumentNode extends ValueNode {
 
+        private int invocationCount;
         final int index;
 
         public ArgumentNode(int index) {
             this.index = index;
         }
 
+        public int getInvocationCount() {
+            return invocationCount;
+        }
+
         @Override
         public Object execute(VirtualFrame frame) {
-            return ((TestArguments) frame.getArguments()).get(index);
+            invocationCount++;
+            return frame.getArguments(TestArguments.class).get(index);
         }
 
     }
--- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java	Sun Apr 28 22:52:12 2013 +0200
@@ -24,6 +24,8 @@
 
 import java.lang.annotation.*;
 
+import com.oracle.truffle.api.nodes.*;
+
 @Retention(RetentionPolicy.CLASS)
 @Target({ElementType.TYPE})
 public @interface NodeChild {
@@ -32,5 +34,14 @@
 
     Class<?> type() default NodeClass.InheritNode.class;
 
+    /**
+     * Executes the {@link NodeChild} with values from other defined {@link NodeChild} elements.
+     * These referenced children must be defined before the current node in the execution order. The
+     * current node {@link #type()} attribute must be set to a {@link Node} which supports the
+     * evaluated execution with the number of {@link #executeWith()} arguments that are defined. For
+     * example if this child is executed with one argument, the {@link #type()} attribute must
+     * define a node which publicly declares a method with the signature
+     * <code>Object execute*(VirtualFrame, Object)</code>.
+     */
     String[] executeWith() default {};
 }
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java	Sun Apr 28 22:52:12 2013 +0200
@@ -35,7 +35,7 @@
  * A guest language can pass its own custom arguments when invoking a Truffle method by creating a
  * subclass of {@link Arguments}. When invoking a call target with
  * {@link CallTarget#call(Arguments)}, the arguments can be passed. A Truffle node can access the
- * arguments passed into the Truffle method by using {@link VirtualFrame#getArguments()}.
+ * arguments passed into the Truffle method by using {@link VirtualFrame#getArguments}.
  * </p>
  * 
  * <p>
@@ -97,7 +97,7 @@
         }
 
         int execute(VirtualFrame frame) {
-            return ((TestArguments) frame.getArguments()).values[index];
+            return frame.getArguments(TestArguments.class).values[index];
         }
     }
 }
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java	Sun Apr 28 22:52:12 2013 +0200
@@ -34,7 +34,7 @@
  * <p>
  * Dynamically typed languages can speculate on the type of a frame slot and only fall back at run
  * time to a more generic type if necessary. The new type of a frame slot can be set using the
- * {@link FrameSlot#setType(Class)} method.
+ * {@link FrameSlot#setKind(FrameSlotKind)} method.
  * </p>
  * 
  * <p>
@@ -48,13 +48,13 @@
     public void test() {
         TruffleRuntime runtime = Truffle.getRuntime();
         FrameDescriptor frameDescriptor = new FrameDescriptor();
-        FrameSlot slot = frameDescriptor.addFrameSlot("localVar", int.class);
+        FrameSlot slot = frameDescriptor.addFrameSlot("localVar", FrameSlotKind.Int);
         TestRootNode rootNode = new TestRootNode(new IntAssignLocal(slot, new StringTestChildNode()), new IntReadLocal(slot));
         CallTarget target = runtime.createCallTarget(rootNode, frameDescriptor);
-        Assert.assertEquals(int.class, slot.getType());
+        Assert.assertEquals(FrameSlotKind.Int, slot.getKind());
         Object result = target.call();
         Assert.assertEquals("42", result);
-        Assert.assertEquals(Object.class, slot.getType());
+        Assert.assertEquals(FrameSlotKind.Object, slot.getKind());
     }
 
     class TestRootNode extends RootNode {
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java	Sun Apr 28 22:52:12 2013 +0200
@@ -35,9 +35,9 @@
  * The frame is the preferred data structure for passing values between nodes. It can in particular
  * be used for storing the values of local variables of the guest language. The
  * {@link FrameDescriptor} represents the current structure of the frame. The method
- * {@link FrameDescriptor#addFrameSlot(Object, Class)} can be used to create predefined frame slots.
- * The setter and getter methods in the {@link Frame} class can be used to access the current value
- * of a particular frame slot.
+ * {@link FrameDescriptor#addFrameSlot(Object, FrameSlotKind)} can be used to create predefined
+ * frame slots. The setter and getter methods in the {@link Frame} class can be used to access the
+ * current value of a particular frame slot.
  * </p>
  * 
  * <p>
@@ -64,7 +64,7 @@
     public void test() {
         TruffleRuntime runtime = Truffle.getRuntime();
         FrameDescriptor frameDescriptor = new FrameDescriptor();
-        FrameSlot slot = frameDescriptor.addFrameSlot("localVar", int.class);
+        FrameSlot slot = frameDescriptor.addFrameSlot("localVar", FrameSlotKind.Int);
         TestRootNode rootNode = new TestRootNode(new AssignLocal(slot), new ReadLocal(slot));
         CallTarget target = runtime.createCallTarget(rootNode, frameDescriptor);
         Object result = target.call();
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java	Sun Apr 28 22:52:12 2013 +0200
@@ -47,13 +47,13 @@
     public void test() {
         TruffleRuntime runtime = Truffle.getRuntime();
         FrameDescriptor frameDescriptor = new FrameDescriptor();
-        FrameSlot slot = frameDescriptor.addFrameSlot("localVar", int.class);
+        FrameSlot slot = frameDescriptor.addFrameSlot("localVar", FrameSlotKind.Int);
         TestRootNode rootNode = new TestRootNode(new IntAssignLocal(slot, new StringTestChildNode()), new IntReadLocal(slot));
         CallTarget target = runtime.createCallTarget(rootNode, frameDescriptor);
-        Assert.assertEquals(int.class, slot.getType());
+        Assert.assertEquals(FrameSlotKind.Int, slot.getKind());
         Object result = target.call();
         Assert.assertEquals("42", result);
-        Assert.assertEquals(Object.class, slot.getType());
+        Assert.assertEquals(FrameSlotKind.Object, slot.getKind());
     }
 
     class TestRootNode extends RootNode {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.api;
 
+import java.lang.annotation.*;
 import java.util.concurrent.*;
 
 /**
@@ -30,7 +31,11 @@
  */
 public class CompilerDirectives {
 
-    private static final double SLOWPATH_PROBABILITY = 0.0001;
+    public static final double LIKELY_PROBABILITY = 0.75;
+    public static final double UNLIKELY_PROBABILITY = 1.0 - LIKELY_PROBABILITY;
+
+    public static final double SLOWPATH_PROBABILITY = 0.0001;
+    public static final double FASTPATH_PROBABILITY = 1.0 - SLOWPATH_PROBABILITY;
 
     /**
      * Directive for the compiler to discontinue compilation at this code position and instead
@@ -62,20 +67,38 @@
     }
 
     /**
-     * Directive for the compiler that the current path has a very low probability to be executed.
-     */
-    public static void slowpath() {
-        injectBranchProbability(SLOWPATH_PROBABILITY);
-    }
-
-    /**
-     * Injects a probability for the current path into the probability information of the
-     * immediately preceeding branch instruction.
+     * Injects a probability for the given condition into the probability information of the
+     * immediately succeeding branch instruction for the condition. The probability must be a value
+     * between 0.0 and 1.0 (inclusive). The condition should not be a combined condition.
+     * 
+     * Example usage immediately before an if statement (it specifies that the likelihood for a to
+     * be greater than b is 90%):
+     * 
+     * <code>
+     * if (injectBranchProbability(0.9, a > b)) {
+     *    // ...
+     * }
+     * </code>
+     * 
+     * Example usage for a combined condition (it specifies that the likelihood for a to be greater
+     * than b is 90% and under the assumption that this is true, the likelihood for a being 0 is
+     * 10%):
+     * 
+     * <code>
+     * if (injectBranchProbability(0.9, a > b) && injectBranchProbability(0.1, a == 0)) {
+     *    // ...
+     * }
+     * </code>
+     * 
+     * There are predefined constants for commonly used probabilities (see
+     * {@link #LIKELY_PROBABILITY} , {@link #UNLIKELY_PROBABILITY}, {@link #SLOWPATH_PROBABILITY},
+     * {@link #FASTPATH_PROBABILITY} ).
      * 
      * @param probability the probability value between 0.0 and 1.0 that should be injected
      */
-    public static void injectBranchProbability(double probability) {
+    public static boolean injectBranchProbability(double probability, boolean condition) {
         assert probability >= 0.0 && probability <= 1.0;
+        return condition;
     }
 
     /**
@@ -85,4 +108,22 @@
      */
     public static void bailout(String reason) {
     }
+
+    /**
+     * Marks fields that should be considered final for a Truffle compilation although they are not
+     * final while executing in the interpreter.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.FIELD})
+    public @interface CompilationFinal {
+    }
+
+    /**
+     * Marks methods that are considered unsafe. Wrong usage of those methods can lead to unexpected
+     * behavior including a crash of the runtime. Therefore, special care should be taken.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.METHOD})
+    public @interface Unsafe {
+    }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java	Sun Apr 28 22:52:12 2013 +0200
@@ -31,26 +31,26 @@
     private final String identifier;
     private final int startLine;
     private final int startColumn;
-    private final int endLine;
-    private final int endColumn;
+    private final int charIndex;
+    private final int charLength;
 
     /**
      * Creates a new object representing a section in the source code of a guest language program.
      * 
      * @param source object representing the source program this is should be a section of
      * @param identifier an identifier used when printing the section
-     * @param startLine the index of the start line of the section (inclusive)
-     * @param startColumn the index of the start column of the section (inclusive)
-     * @param endLine the index of the end line of the section (inclusive)
-     * @param endColumn the index of the end column of the section (inclusive)
+     * @param startLine the index of the start line of the section
+     * @param startColumn the index of the start column of the section
+     * @param charIndex the index of the first character of the section
+     * @param charLength the length of the section in number of characters
      */
-    public SourceSection(Source source, String identifier, int startLine, int startColumn, int endLine, int endColumn) {
+    public SourceSection(Source source, String identifier, int startLine, int startColumn, int charIndex, int charLength) {
         this.source = source;
         this.identifier = identifier;
         this.startLine = startLine;
         this.startColumn = startColumn;
-        this.endLine = endLine;
-        this.endColumn = endColumn;
+        this.charIndex = charIndex;
+        this.charLength = charLength;
     }
 
     /**
@@ -81,21 +81,23 @@
     }
 
     /**
-     * Returns the index of the end line of this source section (inclusive).
+     * Returns the index of the first character of this section. All characters of the source can be
+     * retrieved via the {@link Source#getCode()} method.
      * 
-     * @return the end line
+     * @return the character index
      */
-    public final int getEndLine() {
-        return endLine;
+    public final int getCharIndex() {
+        return charIndex;
     }
 
     /**
-     * Returns the index of the end column of this source section (inclusive).
+     * Returns the length of this section in characters. All characters of the source can be
+     * retrieved via the {@link Source#getCode()} method.
      * 
-     * @return the end column
+     * @return the character length
      */
-    public final int getEndColumn() {
-        return endColumn;
+    public final int getCharLength() {
+        return charLength;
     }
 
     /**
@@ -106,4 +108,19 @@
     public final String getIdentifier() {
         return identifier;
     }
+
+    /**
+     * Returns the code represented by this code section.
+     * 
+     * @return the code as a String object
+     */
+    public final String getCode() {
+        return getSource().getCode().substring(charIndex, charLength);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s:%d", source.getName(), startLine);
+    }
+
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java	Sun Apr 28 22:52:12 2013 +0200
@@ -36,9 +36,17 @@
     FrameDescriptor getFrameDescriptor();
 
     /**
+     * Retrieves the arguments object from this frame. The runtime assumes that the arguments object
+     * is never null. Additionally, the runtime may assume that the given parameter indicating the
+     * class of the arguments object is correct. The runtime is not required to actually check the
+     * type of the arguments object. The parameter must be a value that can be reduced to a compile
+     * time constant.
+     * 
+     * @param clazz the known type of the arguments object as a compile time constant
      * @return the arguments used when calling this method
      */
-    Arguments getArguments();
+    @CompilerDirectives.Unsafe
+    <T extends Arguments> T getArguments(Class<T> clazz);
 
     /**
      * Read access to a local variable of type {@link Object}.
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java	Sun Apr 28 22:52:12 2013 +0200
@@ -53,9 +53,9 @@
         return addFrameSlot(identifier, null);
     }
 
-    public FrameSlot addFrameSlot(Object identifier, Class<?> type) {
+    public FrameSlot addFrameSlot(Object identifier, FrameSlotKind kind) {
         assert !identifierToSlotMap.containsKey(identifier);
-        FrameSlotImpl slot = new FrameSlotImpl(this, identifier, slots.size(), type);
+        FrameSlotImpl slot = new FrameSlotImpl(this, identifier, slots.size(), kind);
         slots.add(slot);
         identifierToSlotMap.put(identifier, slot);
         updateVersion();
@@ -74,12 +74,12 @@
         return addFrameSlot(identifier);
     }
 
-    public FrameSlot findOrAddFrameSlot(Object identifier, Class<?> type) {
+    public FrameSlot findOrAddFrameSlot(Object identifier, FrameSlotKind kind) {
         FrameSlot result = findFrameSlot(identifier);
         if (result != null) {
             return result;
         }
-        return addFrameSlot(identifier, type);
+        return addFrameSlot(identifier, kind);
     }
 
     public int getSize() {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlot.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlot.java	Sun Apr 28 22:52:12 2013 +0200
@@ -31,9 +31,9 @@
 
     int getIndex();
 
-    Class<?> getType();
+    FrameSlotKind getKind();
 
-    void setType(Class<?> type);
+    void setKind(FrameSlotKind kind);
 
     FrameDescriptor getFrameDescriptor();
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotImpl.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotImpl.java	Sun Apr 28 22:52:12 2013 +0200
@@ -27,13 +27,13 @@
     private final FrameDescriptor descriptor;
     private final Object identifier;
     private final int index;
-    private Class<?> type;
+    private FrameSlotKind kind;
 
-    protected FrameSlotImpl(FrameDescriptor descriptor, Object identifier, int index, Class<?> type) {
+    protected FrameSlotImpl(FrameDescriptor descriptor, Object identifier, int index, FrameSlotKind kind) {
         this.descriptor = descriptor;
         this.identifier = identifier;
         this.index = index;
-        this.type = type;
+        this.kind = kind;
     }
 
     public Object getIdentifier() {
@@ -44,19 +44,19 @@
         return index;
     }
 
-    public Class<?> getType() {
-        return type;
+    public FrameSlotKind getKind() {
+        return kind;
     }
 
-    public void setType(final Class<?> type) {
-        assert this.type != type;
-        this.type = type;
+    public void setKind(final FrameSlotKind kind) {
+        assert this.kind != kind;
+        this.kind = kind;
         this.descriptor.updateVersion();
     }
 
     @Override
     public String toString() {
-        return "[" + index + "," + identifier + "," + type + "]";
+        return "[" + index + "," + identifier + "," + kind + "]";
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotKind.java	Sun Apr 28 22:52:12 2013 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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.truffle.api.frame;
+
+public enum FrameSlotKind {
+    Illegal, Object, Long, Int, Double, Float, Boolean;
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameUtil.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameUtil.java	Sun Apr 28 22:52:12 2013 +0200
@@ -33,8 +33,8 @@
      * @param value the new value of the local variable
      */
     public static void setObjectSafe(Frame frame, FrameSlot slot, Object value) {
-        if (slot.getType() != Object.class) {
-            slot.setType(Object.class);
+        if (slot.getKind() != FrameSlotKind.Object) {
+            slot.setKind(FrameSlotKind.Object);
         }
         try {
             frame.setObject(slot, value);
@@ -52,8 +52,8 @@
      * @param value the new value of the local variable
      */
     public static void setBooleanSafe(Frame frame, FrameSlot slot, boolean value) {
-        if (slot.getType() != boolean.class) {
-            slot.setType(boolean.class);
+        if (slot.getKind() != FrameSlotKind.Boolean) {
+            slot.setKind(FrameSlotKind.Boolean);
         }
         try {
             frame.setBoolean(slot, value);
@@ -71,8 +71,8 @@
      * @param value the new value of the local variable
      */
     public static void setIntSafe(Frame frame, FrameSlot slot, int value) {
-        if (slot.getType() != int.class) {
-            slot.setType(int.class);
+        if (slot.getKind() != FrameSlotKind.Int) {
+            slot.setKind(FrameSlotKind.Int);
         }
         try {
             frame.setInt(slot, value);
@@ -90,8 +90,8 @@
      * @param value the new value of the local variable
      */
     public static void setLongSafe(Frame frame, FrameSlot slot, long value) {
-        if (slot.getType() != long.class) {
-            slot.setType(long.class);
+        if (slot.getKind() != FrameSlotKind.Long) {
+            slot.setKind(FrameSlotKind.Long);
         }
         try {
             frame.setLong(slot, value);
@@ -109,8 +109,8 @@
      * @param value the new value of the local variable
      */
     public static void setFloatSafe(Frame frame, FrameSlot slot, float value) {
-        if (slot.getType() != float.class) {
-            slot.setType(float.class);
+        if (slot.getKind() != FrameSlotKind.Float) {
+            slot.setKind(FrameSlotKind.Float);
         }
         try {
             frame.setFloat(slot, value);
@@ -128,8 +128,8 @@
      * @param value the new value of the local variable
      */
     public static void setDoubleSafe(Frame frame, FrameSlot slot, double value) {
-        if (slot.getType() != double.class) {
-            slot.setType(double.class);
+        if (slot.getKind() != FrameSlotKind.Double) {
+            slot.setKind(FrameSlotKind.Double);
         }
         try {
             frame.setDouble(slot, value);
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java	Sun Apr 28 22:52:12 2013 +0200
@@ -38,9 +38,10 @@
         this.arguments = arguments;
     }
 
+    @SuppressWarnings("unchecked")
     @Override
-    public Arguments getArguments() {
-        return arguments;
+    public <T extends Arguments> T getArguments(Class<T> clazz) {
+        return (T) arguments;
     }
 
     @Override
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java	Sun Apr 28 22:52:12 2013 +0200
@@ -34,8 +34,8 @@
     }
 
     @Override
-    public Arguments getArguments() {
-        return wrapped.getArguments();
+    public <T extends Arguments> T getArguments(Class<T> clazz) {
+        return wrapped.getArguments(clazz);
     }
 
     @Override
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Sun Apr 28 22:52:12 2013 +0200
@@ -33,19 +33,20 @@
     private final PackedFrame caller;
     private final Arguments arguments;
     private Object[] locals;
-    private Class[] tags;
+    private byte[] tags;
 
     public DefaultVirtualFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments arguments) {
         this.descriptor = descriptor;
         this.caller = caller;
         this.arguments = arguments;
         this.locals = new Object[descriptor.getSize()];
-        this.tags = new Class[descriptor.getSize()];
+        this.tags = new byte[descriptor.getSize()];
     }
 
+    @SuppressWarnings("unchecked")
     @Override
-    public Arguments getArguments() {
-        return arguments;
+    public <T extends Arguments> T getArguments(Class<T> clazz) {
+        return (T) arguments;
     }
 
     @Override
@@ -65,73 +66,73 @@
 
     @Override
     public Object getObject(FrameSlot slot) throws FrameSlotTypeException {
-        verifyGet(slot, Object.class);
+        verifyGet(slot, FrameSlotKind.Object);
         return locals[slot.getIndex()];
     }
 
     @Override
     public void setObject(FrameSlot slot, Object value) throws FrameSlotTypeException {
-        verifySet(slot, Object.class);
+        verifySet(slot, FrameSlotKind.Object);
         locals[slot.getIndex()] = value;
     }
 
     @Override
     public boolean getBoolean(FrameSlot slot) throws FrameSlotTypeException {
-        verifyGet(slot, boolean.class);
+        verifyGet(slot, FrameSlotKind.Boolean);
         return (boolean) locals[slot.getIndex()];
     }
 
     @Override
     public void setBoolean(FrameSlot slot, boolean value) throws FrameSlotTypeException {
-        verifySet(slot, boolean.class);
+        verifySet(slot, FrameSlotKind.Boolean);
         locals[slot.getIndex()] = value;
     }
 
     @Override
     public int getInt(FrameSlot slot) throws FrameSlotTypeException {
-        verifyGet(slot, int.class);
+        verifyGet(slot, FrameSlotKind.Int);
         return (int) locals[slot.getIndex()];
     }
 
     @Override
     public void setInt(FrameSlot slot, int value) throws FrameSlotTypeException {
-        verifySet(slot, int.class);
+        verifySet(slot, FrameSlotKind.Int);
         locals[slot.getIndex()] = value;
     }
 
     @Override
     public long getLong(FrameSlot slot) throws FrameSlotTypeException {
-        verifyGet(slot, long.class);
+        verifyGet(slot, FrameSlotKind.Long);
         return (long) locals[slot.getIndex()];
     }
 
     @Override
     public void setLong(FrameSlot slot, long value) throws FrameSlotTypeException {
-        verifySet(slot, long.class);
+        verifySet(slot, FrameSlotKind.Long);
         locals[slot.getIndex()] = value;
     }
 
     @Override
     public float getFloat(FrameSlot slot) throws FrameSlotTypeException {
-        verifyGet(slot, float.class);
+        verifyGet(slot, FrameSlotKind.Float);
         return (float) locals[slot.getIndex()];
     }
 
     @Override
     public void setFloat(FrameSlot slot, float value) throws FrameSlotTypeException {
-        verifySet(slot, float.class);
+        verifySet(slot, FrameSlotKind.Float);
         locals[slot.getIndex()] = value;
     }
 
     @Override
     public double getDouble(FrameSlot slot) throws FrameSlotTypeException {
-        verifyGet(slot, double.class);
+        verifyGet(slot, FrameSlotKind.Double);
         return (double) locals[slot.getIndex()];
     }
 
     @Override
     public void setDouble(FrameSlot slot, double value) throws FrameSlotTypeException {
-        verifySet(slot, double.class);
+        verifySet(slot, FrameSlotKind.Double);
         locals[slot.getIndex()] = value;
     }
 
@@ -147,19 +148,19 @@
             assert index >= 0 && index < descriptor.getSize();
             return descriptor.getTypeConversion().getDefaultValue();
         }
-        Class tag = tags[index];
-        if (tag == null) {
+        byte tag = tags[index];
+        if (tag == FrameSlotKind.Illegal.ordinal()) {
             return descriptor.getTypeConversion().getDefaultValue();
         } else {
             return locals[index];
         }
     }
 
-    private void verifySet(FrameSlot slot, Class accessType) throws FrameSlotTypeException {
-        Class<?> slotType = slot.getType();
-        if (slotType != accessType) {
-            if (slotType == null) {
-                slot.setType(accessType);
+    private void verifySet(FrameSlot slot, FrameSlotKind accessKind) throws FrameSlotTypeException {
+        FrameSlotKind slotKind = slot.getKind();
+        if (slotKind != accessKind) {
+            if (slotKind == FrameSlotKind.Illegal) {
+                slot.setKind(accessKind);
             } else {
                 throw new FrameSlotTypeException();
             }
@@ -168,14 +169,14 @@
         if (slotIndex >= tags.length) {
             resize();
         }
-        tags[slotIndex] = accessType;
+        tags[slotIndex] = (byte) accessKind.ordinal();
     }
 
-    private void verifyGet(FrameSlot slot, Class accessType) throws FrameSlotTypeException {
-        Class<?> slotType = slot.getType();
-        if (slotType != accessType) {
-            if (slotType == null && accessType == Object.class) {
-                slot.setType(Object.class);
+    private void verifyGet(FrameSlot slot, FrameSlotKind accessKind) throws FrameSlotTypeException {
+        FrameSlotKind slotKind = slot.getKind();
+        if (slotKind != accessKind) {
+            if (slotKind == FrameSlotKind.Illegal && accessKind == FrameSlotKind.Object) {
+                slot.setKind(FrameSlotKind.Object);
                 this.setObject(slot, descriptor.getTypeConversion().getDefaultValue());
             } else {
                 throw new FrameSlotTypeException();
@@ -185,9 +186,9 @@
         if (slotIndex >= tags.length) {
             resize();
         }
-        if (tags[slotIndex] != accessType) {
+        if (tags[slotIndex] != accessKind.ordinal()) {
             descriptor.getTypeConversion().updateFrameSlot(this, slot, getValue(slot));
-            if (tags[slotIndex] != accessType) {
+            if (tags[slotIndex] != accessKind.ordinal()) {
                 throw new FrameSlotTypeException();
             }
         }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java	Sun Apr 28 22:52:12 2013 +0200
@@ -48,6 +48,7 @@
     private final DeclaredType childAnnotation;
     private final DeclaredType childrenAnnotation;
     private final TypeMirror compilerDirectives;
+    private final TypeMirror compilerAsserts;
 
     private final List<String> errors = new ArrayList<>();
 
@@ -59,6 +60,7 @@
         childAnnotation = getRequired(context, Child.class);
         childrenAnnotation = getRequired(context, Children.class);
         compilerDirectives = getRequired(context, CompilerDirectives.class);
+        compilerAsserts = getRequired(context, CompilerAsserts.class);
         assumption = getRequired(context, Assumption.class);
         invalidAssumption = getRequired(context, InvalidAssumptionException.class);
     }
@@ -118,4 +120,8 @@
     public DeclaredType getChildrenAnnotation() {
         return childrenAnnotation;
     }
+
+    public TypeMirror getCompilerAsserts() {
+        return compilerAsserts;
+    }
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java	Sun Apr 28 22:52:12 2013 +0200
@@ -475,6 +475,19 @@
         currentElement.registerAtEnd(callback);
     }
 
+    public CodeTreeBuilder defaultDeclaration(TypeMirror type, String name) {
+        if (!Utils.isVoid(type)) {
+            startStatement();
+            type(type);
+            string(" ");
+            string(name);
+            string(" = ");
+            defaultValue(type);
+            end(); // statement
+        }
+        return this;
+    }
+
     public CodeTreeBuilder declaration(TypeMirror type, String name, CodeTree init) {
         if (Utils.isVoid(type)) {
             startStatement();
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Sun Apr 28 22:52:12 2013 +0200
@@ -44,8 +44,8 @@
     }
 
     @Override
-    protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData) {
-        List<ExecutableTypeData> execTypes = nodeData.findGenericExecutableTypes(getContext());
+    protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData, int evaluatedCount) {
+        List<ExecutableTypeData> execTypes = nodeData.findGenericExecutableTypes(getContext(), evaluatedCount);
         List<TypeMirror> types = new ArrayList<>();
         for (ExecutableTypeData type : execTypes) {
             types.add(type.getType().getPrimitiveType());
@@ -57,7 +57,7 @@
 
     @Override
     protected ParameterSpec createReturnParameterSpec() {
-        return super.createValueParameterSpec("returnValue", getNode());
+        return super.createValueParameterSpec("returnValue", getNode(), 0);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java	Sun Apr 28 22:52:12 2013 +0200
@@ -22,10 +22,14 @@
  */
 package com.oracle.truffle.codegen.processor.node;
 
+import java.util.*;
+
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
 
+import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
+import com.oracle.truffle.codegen.processor.typesystem.*;
 
 public class NodeChildData extends MessageContainer {
 
@@ -54,6 +58,9 @@
 
     private final Cardinality cardinality;
     private final ExecutionKind executionKind;
+
+    private List<NodeChildData> executeWith = Collections.emptyList();
+
     private NodeData nodeData;
 
     public NodeChildData(Element sourceElement, AnnotationMirror sourceMirror, String name, TypeMirror nodeType, Element accessElement, Cardinality cardinality, ExecutionKind executionKind) {
@@ -66,6 +73,34 @@
         this.executionKind = executionKind;
     }
 
+    public List<NodeChildData> getExecuteWith() {
+        return executeWith;
+    }
+
+    void setExecuteWith(List<NodeChildData> executeWith) {
+        this.executeWith = executeWith;
+    }
+
+    public ExecutableTypeData findExecutableType(ProcessorContext context, TypeData targetType) {
+        ExecutableTypeData executableType = nodeData.findExecutableType(targetType, getExecuteWith().size());
+        if (executableType == null) {
+            executableType = findAnyGenericExecutableType(context);
+        }
+        return executableType;
+    }
+
+    public List<ExecutableTypeData> findGenericExecutableTypes(ProcessorContext context) {
+        return nodeData.findGenericExecutableTypes(context, getExecuteWith().size());
+    }
+
+    public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context) {
+        return nodeData.findAnyGenericExecutableType(context, getExecuteWith().size());
+    }
+
+    public List<ExecutableTypeData> findExecutableTypes() {
+        return nodeData.getExecutableTypes(getExecuteWith().size());
+    }
+
     @Override
     public Element getMessageElement() {
         return sourceElement;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Sun Apr 28 22:52:12 2013 +0200
@@ -43,6 +43,9 @@
 
     private static final String THIS_NODE_LOCAL_VAR_NAME = "thisNode";
 
+    private static final String EXECUTE_GENERIC_NAME = "executeGeneric_";
+    private static final String EXECUTE_SPECIALIZE_NAME = "executeAndSpecialize_";
+
     public NodeCodeGenerator(ProcessorContext context) {
         super(context);
     }
@@ -67,6 +70,10 @@
         return name;
     }
 
+    private static String valueNameEvaluated(ActualParameter targetParameter) {
+        return valueName(targetParameter) + "Evaluated";
+    }
+
     private static String valueName(ActualParameter param) {
         return param.getLocalName();
     }
@@ -92,8 +99,7 @@
         }
     }
 
-    private static void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame,
-                    boolean includeImplicit) {
+    private void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, boolean includeImplicit) {
         if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) {
             builder.string("frameValue");
         }
@@ -122,12 +128,12 @@
         }
     }
 
-    private static String valueName(ActualParameter sourceParameter, ActualParameter targetParameter) {
+    private String valueName(ActualParameter sourceParameter, ActualParameter targetParameter) {
         if (sourceParameter != null) {
             if (!sourceParameter.getSpecification().isSignature()) {
                 return valueName(targetParameter);
             } else if (sourceParameter.getTypeSystemType() != null && targetParameter.getTypeSystemType() != null) {
-                if (sourceParameter.getTypeSystemType().needsCastTo(targetParameter.getTypeSystemType())) {
+                if (sourceParameter.getTypeSystemType().needsCastTo(getContext(), targetParameter.getTypeSystemType())) {
                     return castValueName(targetParameter);
                 }
             }
@@ -137,7 +143,7 @@
         }
     }
 
-    private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) {
+    private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, CodeTree target, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) {
         CodeTreeBuilder builder = parent.create();
 
         boolean castedValues = sourceMethod != targetMethod;
@@ -150,43 +156,47 @@
         TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement());
         NodeData node = (NodeData) targetMethod.getTemplate();
 
-        boolean accessible = targetMethod.canBeAccessedByInstanceOf(getContext(), node.getNodeType());
-        if (accessible) {
-            if (builder.findMethod().getModifiers().contains(STATIC)) {
+        if (target == null) {
+            boolean accessible = targetMethod.canBeAccessedByInstanceOf(getContext(), node.getNodeType());
+            if (accessible) {
+                if (builder.findMethod().getModifiers().contains(STATIC)) {
+                    if (method.getModifiers().contains(STATIC)) {
+                        builder.type(targetClass.asType());
+                    } else {
+                        builder.string(THIS_NODE_LOCAL_VAR_NAME);
+                    }
+                } else {
+                    if (targetMethod instanceof ExecutableTypeData) {
+                        builder.string("this");
+                    } else {
+                        builder.string("super");
+                    }
+                }
+            } else {
                 if (method.getModifiers().contains(STATIC)) {
                     builder.type(targetClass.asType());
                 } else {
-                    builder.string(THIS_NODE_LOCAL_VAR_NAME);
-                }
-            } else {
-                if (targetMethod instanceof ExecutableTypeData) {
-                    builder.string("this");
-                } else {
-                    builder.string("super");
+                    ActualParameter parameter = null;
+                    for (ActualParameter searchParameter : targetMethod.getParameters()) {
+                        if (searchParameter.getSpecification().isSignature()) {
+                            parameter = searchParameter;
+                            break;
+                        }
+                    }
+                    ActualParameter sourceParameter = sourceMethod.findParameter(parameter.getLocalName());
+                    assert parameter != null;
+
+                    if (castedValues && sourceParameter != null) {
+                        builder.string(valueName(sourceParameter, parameter));
+                    } else {
+                        builder.string(valueName(parameter));
+                    }
                 }
             }
+            builder.string(".");
         } else {
-            if (method.getModifiers().contains(STATIC)) {
-                builder.type(targetClass.asType());
-            } else {
-                ActualParameter parameter = null;
-                for (ActualParameter searchParameter : targetMethod.getParameters()) {
-                    if (searchParameter.getSpecification().isSignature()) {
-                        parameter = searchParameter;
-                        break;
-                    }
-                }
-                ActualParameter sourceParameter = sourceMethod.findParameter(parameter.getLocalName());
-                assert parameter != null;
-
-                if (castedValues && sourceParameter != null) {
-                    builder.string(valueName(sourceParameter, parameter));
-                } else {
-                    builder.string(valueName(parameter));
-                }
-            }
+            builder.tree(target);
         }
-        builder.string(".");
         builder.startCall(method.getSimpleName().toString());
 
         for (ActualParameter targetParameter : targetMethod.getParameters()) {
@@ -236,41 +246,16 @@
         return builder.getRoot();
     }
 
-    private static String genClassName(NodeData node) {
+    private static String baseClassName(NodeData node) {
         String nodeid = node.getNodeId();
         if (nodeid.endsWith("Node") && !nodeid.equals("Node")) {
             nodeid = nodeid.substring(0, nodeid.length() - 4);
         }
         String name = Utils.firstLetterUpperCase(nodeid);
-        name += "GenNode";
+        name += "BaseNode";
         return name;
     }
 
-    private String generatedGenericMethodName(SpecializationData specialization) {
-        final String prefix = "generic";
-
-        if (specialization == null) {
-            return prefix;
-        }
-
-        if (!specialization.getNode().needsRewrites(context)) {
-            return prefix;
-        }
-
-        SpecializationData prev = null;
-        for (SpecializationData current : specialization.getNode().getSpecializations()) {
-            if (specialization == current) {
-                if (prev == null || prev.isUninitialized()) {
-                    return prefix;
-                } else {
-                    return prefix + current.getId();
-                }
-            }
-            prev = current;
-        }
-        return prefix;
-    }
-
     private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, CodeTree value) {
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
         startCallTypeSystemMethod(context, builder, node, methodName);
@@ -304,14 +289,20 @@
             // find out which values needs a cast
             valuesNeedsCast = new HashSet<>();
             for (GuardData guard : targetSpecialization.getGuards()) {
-                for (ActualParameter parameter : guard.getParameters()) {
-                    NodeChildData field = node.findChild(parameter.getSpecification().getName());
+                for (ActualParameter targetParameter : guard.getParameters()) {
+                    NodeChildData field = node.findChild(targetParameter.getSpecification().getName());
                     if (field == null) {
                         continue;
                     }
-                    TypeData typeData = parameter.getTypeSystemType();
-                    if (typeData != null && !typeData.isGeneric()) {
-                        valuesNeedsCast.add(parameter.getLocalName());
+                    TypeData targetType = targetParameter.getTypeSystemType();
+                    ActualParameter sourceParameter = sourceSpecialization.findParameter(targetParameter.getLocalName());
+                    if (sourceParameter == null) {
+                        sourceParameter = targetParameter;
+                    }
+                    TypeData sourceType = sourceParameter.getTypeSystemType();
+
+                    if (sourceType.needsCastTo(getContext(), targetType)) {
+                        valuesNeedsCast.add(targetParameter.getLocalName());
                     }
                 }
             }
@@ -353,14 +344,14 @@
         return builder.getRoot();
     }
 
-    private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) {
+    private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, TemplateMethod valueSpecialization, SpecializationData guardedSpecialization) {
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
         String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
         if (guardedSpecialization.getGuards().size() > 0) {
             // Explicitly specified guards
             for (GuardData guard : guardedSpecialization.getGuards()) {
                 builder.string(andOperator);
-                builder.tree(createTemplateMethodCall(parent, valueSpecialization, guard, null));
+                builder.tree(createTemplateMethodCall(parent, null, valueSpecialization, guard, null));
                 andOperator = " && ";
             }
         }
@@ -368,7 +359,7 @@
         return builder.isEmpty() ? null : builder.getRoot();
     }
 
-    private CodeTree createCasts(CodeTreeBuilder parent, Set<String> castWhiteList, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) {
+    private CodeTree createCasts(CodeTreeBuilder parent, Set<String> castWhiteList, TemplateMethod valueSpecialization, SpecializationData guardedSpecialization) {
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
         // Implict guards based on method signature
         for (ActualParameter guardedParam : guardedSpecialization.getParameters()) {
@@ -378,6 +369,14 @@
             }
             ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName());
 
+            if (valueParam == null) {
+                /*
+                 * If used inside a function execute method. The value param may not exist. In that
+                 * case it assumes that the value is already converted.
+                 */
+                valueParam = guardedParam;
+            }
+
             if (castWhiteList != null && !castWhiteList.contains(guardedParam.getLocalName())) {
                 continue;
             }
@@ -398,15 +397,9 @@
         String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
 
         if (emitAssumptions) {
-            boolean isStatic = parent.findMethod().getModifiers().contains(STATIC);
-
             for (String assumption : guardedSpecialization.getAssumptions()) {
                 builder.string(andOperator);
-                if (isStatic) {
-                    builder.string(THIS_NODE_LOCAL_VAR_NAME);
-                } else {
-                    builder.string("this");
-                }
+                builder.string("this");
                 builder.string(".").string(assumption).string(".isValid()");
                 andOperator = " && ";
             }
@@ -419,6 +412,14 @@
             }
             ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName());
 
+            if (valueParam == null) {
+                /*
+                 * If used inside a function execute method. The value param may not exist. In that
+                 * case it assumes that the value is already converted.
+                 */
+                valueParam = guardedParam;
+            }
+
             CodeTree implicitGuard = createImplicitGuard(builder, field, valueParam, guardedParam);
             if (implicitGuard == null) {
                 continue;
@@ -439,7 +440,7 @@
         TypeData targetType = target.getTypeSystemType();
         TypeData sourceType = source.getTypeSystemType();
 
-        if (targetType.equalsType(sourceType) || targetType.isGeneric()) {
+        if (!sourceType.needsCastTo(getContext(), targetType)) {
             return null;
         }
 
@@ -471,7 +472,7 @@
         TypeData sourceType = source.getTypeSystemType();
         TypeData targetType = target.getTypeSystemType();
 
-        if (!sourceType.needsCastTo(targetType)) {
+        if (!sourceType.needsCastTo(getContext(), targetType)) {
             return null;
         }
 
@@ -570,6 +571,16 @@
         return true;
     }
 
+    private static CodeTree createReturnNewSpecialization(CodeTreeBuilder parent, SpecializationData specialization, String thisLocalVariableName, boolean hasCopyConstructor) {
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+        builder.startReturn().startNew(nodeSpecializationClassName(specialization));
+        if (hasCopyConstructor) {
+            builder.string(thisLocalVariableName);
+        }
+        builder.end().end();
+        return builder.getRoot();
+    }
+
     @Override
     protected void createChildren(NodeData node) {
         Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>();
@@ -585,15 +596,15 @@
         }
     }
 
-    private class NodeGenFactory extends ClassElementFactory<NodeData> {
+    private class NodeBaseFactory extends ClassElementFactory<NodeData> {
 
-        public NodeGenFactory(ProcessorContext context) {
+        public NodeBaseFactory(ProcessorContext context) {
             super(context);
         }
 
         @Override
         protected CodeTypeElement create(NodeData node) {
-            CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), genClassName(node), node.getNodeType(), false);
+            CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), baseClassName(node), node.getNodeType(), false);
 
             for (NodeChildData child : node.getChildren()) {
                 clazz.add(createChildField(child));
@@ -620,6 +631,19 @@
             return clazz;
         }
 
+        @Override
+        protected void createChildren(NodeData node) {
+            CodeTypeElement clazz = getElement();
+
+            if (node.needsRewrites(context)) {
+                clazz.add(createGenericExecute(node, EXECUTE_SPECIALIZE_NAME, true));
+            }
+
+            if (node.getGenericSpecialization() != null) {
+                clazz.add(createGenericExecute(node, EXECUTE_GENERIC_NAME, false));
+            }
+        }
+
         private void createConstructors(NodeData node, CodeTypeElement clazz) {
             List<ExecutableElement> constructors = findUserConstructors(node.getNodeType());
             if (constructors.isEmpty()) {
@@ -720,6 +744,162 @@
             var.getAnnotationMirrors().add(new CodeAnnotationMirror(annotationType));
             return var;
         }
+
+        private CodeExecutableElement createGenericExecute(NodeData node, String name, boolean specialize) {
+            TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType();
+
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, name);
+            CodeTreeBuilder builder = method.createBuilder();
+
+            String prefix = null;
+            if (specialize) {
+                method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
+
+                builder.startStatement();
+                builder.startStaticCall(getContext().getTruffleTypes().getCompilerAsserts(), "neverPartOfCompilation").end();
+                builder.end();
+
+                emitSpecializationListeners(builder, node);
+                builder.defaultDeclaration(node.getGenericSpecialization().getReturnSignature().getPrimitiveType(), "result");
+                if (node.getGenericSpecialization().isUseSpecializationsForGeneric()) {
+                    builder.defaultDeclaration(getContext().getType(boolean.class), "resultIsSet");
+                }
+                builder.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end();
+                prefix = null;
+            }
+
+            addInternalValueParameters(method, node.getGenericSpecialization(), true);
+
+            List<SpecializationData> specializations = node.getSpecializations();
+            if (!specialize && !node.getGenericSpecialization().isUseSpecializationsForGeneric()) {
+                specializations = Arrays.asList(node.getGenericSpecialization());
+            }
+
+            // group specializations for reachabiltiy
+            List<SpecializationData> unreachableSpecializations = new ArrayList<>();
+            List<SpecializationData> filteredSpecializations = new ArrayList<>();
+            if (!specialize) {
+                unreachableSpecializations = new ArrayList<>();
+                filteredSpecializations = new ArrayList<>();
+                boolean unreachable = false;
+                for (SpecializationData specialization : specializations) {
+                    if (unreachable) {
+                        unreachableSpecializations.add(specialization);
+                    } else {
+                        filteredSpecializations.add(specialization);
+                        if (!specialization.isUninitialized() && !specialization.hasRewrite(getContext())) {
+                            unreachable = true;
+                        }
+                    }
+                }
+            } else {
+                unreachableSpecializations = Collections.emptyList();
+                filteredSpecializations = specializations;
+            }
+
+            for (SpecializationData current : filteredSpecializations) {
+                if (current.isUninitialized()) {
+                    continue;
+                }
+                CodeTreeBuilder execute = new CodeTreeBuilder(builder);
+
+                execute.tree(createGenericInvoke(builder, current, specialize));
+
+                if (specialize && !current.isGeneric()) {
+                    builder.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(current)).string(".class)").end();
+                }
+
+                builder.tree(createGuardAndCast(builder, prefix, current.getNode().getGenericSpecialization(), current, true, execute.getRoot(), null, true));
+            }
+
+            for (SpecializationData specializationData : unreachableSpecializations) {
+                builder.string("// unreachable ").string(specializationData.getId()).newLine();
+            }
+
+            return method;
+        }
+
+        private CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData current, boolean specialize) {
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+
+            if (!current.getExceptions().isEmpty()) {
+                builder.startTryBlock();
+            }
+
+            CodeTree executeCall = null;
+            if (current.getMethod() != null) {
+                executeCall = createTemplateMethodCall(builder, null, current.getNode().getGenericSpecialization(), current, null);
+            }
+
+            if (specialize && executeCall == null && !current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) {
+                emitEncounteredSynthetic(builder);
+            } else if (specialize) {
+
+                if (current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) {
+                    builder.startIf().string("!resultIsSet").end().startBlock();
+                    if (executeCall != null) {
+                        if (current.getReturnSignature().isVoid()) {
+                            builder.statement(executeCall);
+                        } else {
+                            builder.startStatement().string("result = ").tree(executeCall).end();
+                        }
+                        builder.statement("resultIsSet = true");
+                    } else {
+                        emitEncounteredSynthetic(builder);
+                    }
+                    builder.end();
+                }
+
+                if (!current.isGeneric()) {
+                    builder.startIf().string("allowed").end().startBlock();
+                }
+
+                if (!current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) {
+                    if (current.getReturnSignature().isVoid()) {
+                        builder.statement(executeCall);
+                    } else {
+                        builder.startStatement().string("result = ").tree(executeCall).end();
+                    }
+                }
+
+                builder.startStatement().startCall("super", "replace");
+                builder.startGroup().startNew(nodeSpecializationClassName(current)).string("this").end().end();
+                builder.end().end();
+
+                if (current.getReturnSignature().isVoid()) {
+                    builder.returnStatement();
+                } else {
+                    builder.startReturn().string("result").end();
+                }
+                if (!current.isGeneric()) {
+                    builder.end();
+                }
+            } else {
+                if (executeCall == null) {
+                    emitEncounteredSynthetic(builder);
+                } else {
+                    builder.startReturn().tree(executeCall).end();
+                }
+            }
+
+            if (!current.getExceptions().isEmpty()) {
+                for (SpecializationThrowsData exception : current.getExceptions()) {
+                    builder.end().startCatchBlock(exception.getJavaClass(), "rewriteEx");
+                    builder.string("// fall through").newLine();
+                }
+                builder.end();
+            }
+
+            return builder.getRoot();
+        }
+
+        private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) {
+            for (TemplateMethod listener : node.getSpecializationListeners()) {
+                builder.startStatement();
+                builder.tree(createTemplateMethodCall(builder, null, listener, listener, null));
+                builder.end(); // statement
+            }
+        }
     }
 
     private class NodeFactoryFactory extends ClassElementFactory<NodeData> {
@@ -752,23 +932,15 @@
             Modifier createVisibility = Utils.getVisibility(clazz.getModifiers());
 
             if (node.needsFactory()) {
-                NodeGenFactory factory = new NodeGenFactory(context);
+                NodeBaseFactory factory = new NodeBaseFactory(context);
                 add(factory, node);
                 generatedNode = factory.getElement();
 
-                createFactoryMethods(node, clazz, createVisibility);
-
                 if (node.needsRewrites(context)) {
                     clazz.add(createCreateSpecializedMethod(node, createVisibility));
-                    clazz.add(createSpecializeMethod(node));
                 }
 
-                if (node.getGenericSpecialization() != null) {
-                    List<CodeExecutableElement> genericMethods = createGeneratedGenericMethod(node);
-                    for (CodeExecutableElement method : genericMethods) {
-                        clazz.add(method);
-                    }
-                }
+                createFactoryMethods(node, clazz, createVisibility);
 
                 for (SpecializationData specialization : node.getSpecializations()) {
                     add(new SpecializedNodeFactory(context, generatedNode), specialization);
@@ -1145,125 +1317,6 @@
             return method;
         }
 
-        private CodeExecutableElement createSpecializeMethod(NodeData node) {
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), node.getNodeType(), "specialize");
-            method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME));
-            method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
-            addInternalValueParameters(method, node.getGenericSpecialization(), true);
-
-            CodeTreeBuilder body = method.createBuilder();
-            body.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end();
-
-            boolean hasCopyConstructor = findCopyConstructor(generatedNode.asType()) != null;
-
-            for (int i = 1; i < node.getSpecializations().size(); i++) {
-                SpecializationData specialization = node.getSpecializations().get(i);
-                body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(specialization)).string(".class)").end();
-
-                CodeTree guarded = createReturnNewSpecialization(body, specialization, THIS_NODE_LOCAL_VAR_NAME, hasCopyConstructor);
-
-                body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, false, guarded, null, true));
-            }
-            body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end();
-
-            return method;
-        }
-
-        private CodeTree createReturnNewSpecialization(CodeTreeBuilder parent, SpecializationData specialization, String thisLocalVariableName, boolean hasCopyConstructor) {
-            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-            builder.startReturn().startNew(nodeSpecializationClassName(specialization));
-            if (hasCopyConstructor) {
-                builder.string(thisLocalVariableName);
-            }
-            builder.end().end();
-            return builder.getRoot();
-        }
-
-        private List<CodeExecutableElement> createGeneratedGenericMethod(NodeData node) {
-            TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType();
-            if (node.needsRewrites(context)) {
-                List<CodeExecutableElement> methods = new ArrayList<>();
-
-                List<SpecializationData> specializations = node.getSpecializations();
-                SpecializationData prev = null;
-                for (int i = 0; i < specializations.size(); i++) {
-                    SpecializationData current = specializations.get(i);
-                    SpecializationData next = i + 1 < specializations.size() ? specializations.get(i + 1) : null;
-                    if (prev == null || current.isUninitialized()) {
-                        prev = current;
-                        continue;
-                    } else {
-                        String methodName = generatedGenericMethodName(current);
-                        CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, methodName);
-                        method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME));
-                        addInternalValueParameters(method, node.getGenericSpecialization(), true);
-
-                        emitGeneratedGenericSpecialization(method.createBuilder(), current, next);
-
-                        methods.add(method);
-                    }
-                    prev = current;
-                }
-
-                return methods;
-            } else {
-                CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, generatedGenericMethodName(null));
-                method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME));
-                addInternalValueParameters(method, node.getGenericSpecialization(), true);
-                emitInvokeDoMethod(method.createBuilder(), node.getGenericSpecialization(), 0);
-                return Arrays.asList(method);
-            }
-        }
-
-        private void emitGeneratedGenericSpecialization(CodeTreeBuilder builder, SpecializationData current, SpecializationData next) {
-            CodeTreeBuilder invokeMethodBuilder = new CodeTreeBuilder(builder);
-            emitInvokeDoMethod(invokeMethodBuilder, current, 0);
-            CodeTree invokeMethod = invokeMethodBuilder.getRoot();
-
-            if (next != null) {
-                CodeTreeBuilder nextBuilder = builder.create();
-
-                nextBuilder.startReturn().startCall(generatedGenericMethodName(next));
-                nextBuilder.string(THIS_NODE_LOCAL_VAR_NAME);
-                addInternalValueParameterNames(nextBuilder, next, next, null, true, true);
-                nextBuilder.end().end();
-
-                invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, true, invokeMethod, nextBuilder.getRoot(), true);
-            }
-
-            builder.tree(invokeMethod);
-
-            if (next != null) {
-                builder.end();
-            }
-        }
-
-        private void emitInvokeDoMethod(CodeTreeBuilder builder, SpecializationData specialization, int level) {
-            if (!specialization.getExceptions().isEmpty()) {
-                builder.startTryBlock();
-            }
-
-            if (specialization.getMethod() == null) {
-                emitEncounteredSynthetic(builder);
-            } else {
-                builder.startReturn();
-                builder.tree(createTemplateMethodCall(builder, specialization.getNode().getGenericSpecialization(), specialization, null));
-                builder.end(); // return
-            }
-
-            if (!specialization.getExceptions().isEmpty()) {
-                for (SpecializationThrowsData exception : specialization.getExceptions()) {
-                    builder.end().startCatchBlock(exception.getJavaClass(), "ex" + level);
-
-                    builder.startReturn().startCall(generatedGenericMethodName(exception.getTransitionTo()));
-                    builder.string(THIS_NODE_LOCAL_VAR_NAME);
-                    addInternalValueParameterNames(builder, exception.getTransitionTo(), exception.getTransitionTo(), null, true, true);
-                    builder.end().end();
-                }
-                builder.end();
-            }
-        }
-
     }
 
     private class SpecializedNodeFactory extends ClassElementFactory<SpecializationData> {
@@ -1313,10 +1366,6 @@
                     clazz.remove(executeMethod);
                 }
             }
-
-            if (specialization.hasRewrite(getContext())) {
-                buildSpecializeAndExecute(clazz, specialization);
-            }
         }
 
         private CodeTree createExecuteBody(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData execType) {
@@ -1343,7 +1392,12 @@
             int i = 0;
             for (VariableElement param : method.getParameters()) {
                 CodeVariableElement var = CodeVariableElement.clone(param);
-                var.setName(valueName(execType.getParameters().get(i)));
+                ActualParameter actualParameter = execType.getParameters().get(i);
+                if (actualParameter.getSpecification().isSignature()) {
+                    var.setName(valueNameEvaluated(actualParameter));
+                } else {
+                    var.setName(valueName(actualParameter));
+                }
                 method.getParameters().set(i, var);
                 i++;
             }
@@ -1398,7 +1452,7 @@
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             NodeData node = specialization.getNode();
 
-            ExecutableTypeData castedType = node.findExecutableType(type);
+            ExecutableTypeData castedType = node.findExecutableType(type, 0);
             TypeData primaryType = castExecutable.getType();
 
             boolean needsTry = castExecutable.hasUnexpectedValue(getContext());
@@ -1413,17 +1467,13 @@
 
                 ActualParameter targetParameter = castExecutable.findParameter(sourceParameter.getLocalName());
                 if (targetParameter != null) {
-                    TypeData sourceType = sourceParameter.getTypeSystemType();
-                    TypeData targetType = targetParameter.getTypeSystemType();
-                    if (sourceType.needsCastTo(targetType)) {
-                        executeParameters.add(targetParameter);
-                    }
+                    executeParameters.add(targetParameter);
                 }
             }
 
             builder.tree(createExecuteChildren(builder, executable, specialization, executeParameters, null, true));
 
-            CodeTree primaryExecuteCall = createTemplateMethodCall(builder, executable, castExecutable, null);
+            CodeTree primaryExecuteCall = createTemplateMethodCall(builder, null, executable, castExecutable, null);
             if (needsTry) {
                 if (!returnVoid) {
                     builder.declaration(primaryType.getPrimitiveType(), "value");
@@ -1444,14 +1494,14 @@
                     builder.string("// ignore").newLine();
                 } else {
                     builder.startReturn();
-                    builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("ex.getResult()")));
+                    builder.tree(createExpectExecutableType(node, specialization.getNode().getTypeSystem().getGenericTypeData(), castedType, CodeTreeBuilder.singleString("ex.getResult()")));
                     builder.end();
                 }
                 builder.end();
 
                 if (!returnVoid) {
                     builder.startReturn();
-                    builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("value")));
+                    builder.tree(createExpectExecutableType(node, castExecutable.getReturnSignature(), executable, CodeTreeBuilder.singleString("value")));
                     builder.end();
                 }
             } else {
@@ -1459,7 +1509,7 @@
                     builder.statement(primaryExecuteCall);
                 } else {
                     builder.startReturn();
-                    builder.tree(createExpectType(node, castedType, primaryExecuteCall));
+                    builder.tree(createExpectExecutableType(node, castExecutable.getReturnSignature(), executable, primaryExecuteCall));
                     builder.end();
                 }
             }
@@ -1467,21 +1517,24 @@
             return builder.getRoot();
         }
 
-        private CodeTree createExpectType(NodeData node, ExecutableTypeData castedType, CodeTree value) {
-            if (castedType == null) {
+        private CodeTree createExpectExecutableType(NodeData node, TypeData sourceType, ExecutableTypeData castedType, CodeTree value) {
+            boolean hasUnexpected = castedType.hasUnexpectedValue(getContext());
+            return createCastType(node, sourceType, castedType.getType(), hasUnexpected, value);
+        }
+
+        private CodeTree createCastType(NodeData node, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) {
+            if (targetType == null) {
                 return value;
-            } else if (castedType.getType().isVoid()) {
-                return value;
-            } else if (castedType.getType().isGeneric()) {
+            } else if (!sourceType.needsCastTo(getContext(), targetType)) {
                 return value;
             }
 
             CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
             String targetMethodName;
-            if (castedType.hasUnexpectedValue(getContext())) {
-                targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(castedType.getType());
+            if (expect) {
+                targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType);
             } else {
-                targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(castedType.getType());
+                targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType);
             }
             startCallTypeSystemMethod(getContext(), builder, node, targetMethodName);
 
@@ -1499,15 +1552,15 @@
             builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null, false));
 
             CodeTree executeNode;
-            if (specialization.isUninitialized()) {
-                builder.tree(createSpecializeCall(builder, executable, specialization));
-            }
             executeNode = createExecute(builder, executable, specialization);
 
             SpecializationData next = specialization.findNextSpecialization();
             CodeTree returnSpecialized = null;
             if (next != null) {
-                returnSpecialized = createReturnSpecializeAndExecute(builder, executable, next, null);
+                CodeTreeBuilder returnBuilder = new CodeTreeBuilder(builder);
+                returnBuilder.tree(createDeoptimize(builder));
+                returnBuilder.tree(createReturnExecuteAndSpecialize(builder, executable, next, null));
+                returnSpecialized = returnBuilder.getRoot();
             }
             builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized, false));
 
@@ -1522,28 +1575,6 @@
             return builder.getRoot();
         }
 
-        private CodeTree createSpecializeCall(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) {
-            NodeData node = specialization.getNode();
-
-            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-            emitSpecializationListeners(builder, node);
-
-            builder.startStatement();
-            builder.startCall("replace");
-            if (node.needsRewrites(getContext())) {
-                builder.startCall(factoryClassName(node), "specialize");
-                builder.string("this");
-                builder.typeLiteral(builder.findMethod().getEnclosingElement().asType());
-                addInternalValueParameterNames(builder, executable, specialization, null, true, true);
-                builder.end(); // call replace, call specialize
-            } else {
-                builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end();
-            }
-            builder.end().end();
-            emitSpecializationListeners(builder, node);
-            return builder.getRoot();
-        }
-
         private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) {
             NodeData node = specialization.getNode();
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
@@ -1559,27 +1590,18 @@
 
             CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent);
             if (specialization.isUninitialized()) {
-                String genericMethodName = generatedGenericMethodName(null);
-                returnBuilder.startCall(factoryClassName(node), genericMethodName);
-                returnBuilder.string("this");
-                addInternalValueParameterNames(returnBuilder, executable, specialization, null, true, true);
+                returnBuilder.startCall("super", EXECUTE_SPECIALIZE_NAME);
+                returnBuilder.startGroup().string(nodeSpecializationClassName(specialization)).string(".class").end();
+                addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true);
                 returnBuilder.end();
             } else if (specialization.getMethod() == null && !node.needsRewrites(context)) {
                 emitEncounteredSynthetic(builder);
             } else if (specialization.isGeneric()) {
-                String genericMethodName;
-                if (!specialization.isUseSpecializationsForGeneric()) {
-                    genericMethodName = generatedGenericMethodName(specialization);
-                } else {
-                    genericMethodName = generatedGenericMethodName(null);
-                }
-
-                returnBuilder.startCall(factoryClassName(node), genericMethodName);
-                returnBuilder.string("this");
-                addInternalValueParameterNames(returnBuilder, executable, specialization, null, true, true);
+                returnBuilder.startCall("super", EXECUTE_GENERIC_NAME);
+                addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true);
                 returnBuilder.end();
             } else {
-                returnBuilder.tree(createTemplateMethodCall(returnBuilder, executable, specialization, null));
+                returnBuilder.tree(createTemplateMethodCall(returnBuilder, null, specialization, specialization, null));
             }
 
             if (!returnBuilder.isEmpty()) {
@@ -1590,7 +1612,7 @@
 
                 if (targetType == null || sourceType == null) {
                     builder.tree(returnBuilder.getRoot());
-                } else if (sourceType.needsCastTo(targetType)) {
+                } else if (sourceType.needsCastTo(getContext(), targetType)) {
                     builder.tree(createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.expectTypeMethodName(targetType), returnBuilder.getRoot()));
                 } else {
                     builder.tree(returnBuilder.getRoot());
@@ -1601,13 +1623,14 @@
             if (!specialization.getExceptions().isEmpty()) {
                 for (SpecializationThrowsData exception : specialization.getExceptions()) {
                     builder.end().startCatchBlock(exception.getJavaClass(), "ex");
-                    builder.tree(createReturnSpecializeAndExecute(parent, executable, exception.getTransitionTo(), null));
+                    builder.tree(createDeoptimize(builder));
+                    builder.tree(createReturnExecuteAndSpecialize(parent, executable, exception.getTransitionTo(), null));
                 }
                 builder.end();
             }
             if (!specialization.getAssumptions().isEmpty()) {
                 builder.end().startCatchBlock(getContext().getTruffleTypes().getInvalidAssumption(), "ex");
-                builder.tree(createReturnSpecializeAndExecute(parent, executable, specialization.findNextSpecialization(), null));
+                builder.tree(createReturnExecuteAndSpecialize(parent, executable, specialization.findNextSpecialization(), null));
                 builder.end();
             }
 
@@ -1627,50 +1650,53 @@
                 }
                 TypeData targetType = targetParameter.getTypeSystemType();
 
-                ExecutableTypeData targetExecutable = field.getNodeData().findExecutableType(targetType);
+                ExecutableTypeData targetExecutable = field.findExecutableType(getContext(), targetType);
 
                 ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName());
 
-                String targetVariableName = null;
+                String targetVariableName = valueName(targetParameter);
                 CodeTree executionExpression = null;
                 if (cast || sourceParameter != null) {
                     TypeData sourceType = sourceParameter.getTypeSystemType();
-                    if (!sourceType.needsCastTo(targetType)) {
+                    if (!sourceType.needsCastTo(getContext(), targetType)) {
                         if (field.isShortCircuit() && sourceParameter != null) {
-                            builder.tree(createShortCircuitValue(builder, sourceExecutable, specialization, field, targetParameter.getPreviousParameter(), unexpectedParameter));
+                            builder.tree(createShortCircuitValue(builder, specialization, field, targetParameter.getPreviousParameter(), unexpectedParameter));
                         }
-                        continue;
+                        builder.startStatement();
+                        builder.type(targetParameter.getType()).string(" ");
+                        builder.string(valueName(targetParameter)).string(" = ");
+                        builder.tree(CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter)));
+                        builder.end();
+                    } else {
+                        executionExpression = createExpectExecutableType(sourceNode, sourceType, targetExecutable, CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter)));
                     }
-                    executionExpression = createExpectType(sourceNode, targetExecutable, CodeTreeBuilder.singleString(valueName(targetParameter)));
-                    targetVariableName = castValueName(targetParameter);
                 } else if (sourceParameter == null) {
-                    targetVariableName = valueName(targetParameter);
-                    executionExpression = createExecuteChildExpression(builder, field, targetParameter);
+                    executionExpression = createExecuteChildExpression(builder, field, targetParameter, unexpectedParameter);
                 }
 
-                CodeTreeVariable executionVar = new CodeTreeVariable();
-                CodeTree shortCircuitTree = createShortCircuitTree(builder, executionVar, targetVariableName, sourceExecutable, specialization, targetParameter, unexpectedParameter);
-                CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpression, targetVariableName, specialization, sourceExecutable, targetExecutable, targetParameter,
-                                shortCircuitTree != executionVar);
+                if (executionExpression != null) {
+                    CodeTreeVariable executionVar = new CodeTreeVariable();
+                    CodeTree shortCircuitTree = createShortCircuitTree(builder, executionVar, targetVariableName, specialization, targetParameter, unexpectedParameter);
+                    CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpression, targetVariableName, specialization, sourceExecutable, targetExecutable, targetParameter,
+                                    shortCircuitTree != executionVar);
 
-                executionVar.set(unexpectedTree);
-                builder.tree(shortCircuitTree);
+                    executionVar.set(unexpectedTree);
+                    builder.tree(shortCircuitTree);
+                }
             }
             return builder.getRoot();
         }
 
-        private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) {
-            for (TemplateMethod listener : node.getSpecializationListeners()) {
-                builder.startStatement();
-                builder.tree(createTemplateMethodCall(builder, listener, listener, null));
-                builder.end(); // statement
-            }
-        }
-
         private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ExecutableTypeData currentExecutable,
                         ExecutableTypeData targetExecutable, ActualParameter param, boolean shortCircuit) {
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             boolean unexpected = targetExecutable.hasUnexpectedValue(getContext());
+            boolean cast = false;
+            if (targetExecutable.getType().needsCastTo(getContext(), param.getTypeSystemType())) {
+                unexpected = true;
+                cast = true;
+            }
+
             builder.startStatement();
 
             if (!shortCircuit) {
@@ -1689,7 +1715,11 @@
                 builder.string(targetVariableName);
             }
             builder.string(" = ");
-            builder.tree(body);
+            if (cast) {
+                builder.tree(createCastType(specialization.getNode(), targetExecutable.getType(), param.getTypeSystemType(), true, body));
+            } else {
+                builder.tree(body);
+            }
             builder.end();
 
             if (unexpected) {
@@ -1698,17 +1728,18 @@
                 ActualParameter genericParameter = generic.findParameter(param.getLocalName());
 
                 List<ActualParameter> genericParameters = generic.getParametersAfter(genericParameter);
+                builder.tree(createDeoptimize(builder));
                 builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter, false));
-                builder.tree(createReturnSpecializeAndExecute(builder, currentExecutable, specialization.findNextSpecialization(), param));
+                builder.tree(createReturnExecuteAndSpecialize(builder, currentExecutable, specialization.findNextSpecialization(), param));
                 builder.end(); // catch block
             }
 
             return builder.getRoot();
         }
 
-        private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData targetField, ActualParameter sourceParameter) {
+        private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData targetField, ActualParameter sourceParameter, ActualParameter unexpectedParameter) {
             TypeData type = sourceParameter.getTypeSystemType();
-            ExecutableTypeData execType = targetField.getNodeData().findExecutableType(type);
+            ExecutableTypeData execType = targetField.findExecutableType(getContext(), type);
 
             /*
              * FIXME Temporary deactivated due to partial evaluation failure else if
@@ -1730,16 +1761,47 @@
                 }
                 builder.string(".");
             }
+
             builder.startCall(execType.getMethodName());
-            if (execType.getParameters().size() == 1) {
-                builder.string("frameValue");
+
+            List<ActualParameter> signatureParameters = getModel().getSignatureParameters();
+            int index = 0;
+            for (ActualParameter parameter : execType.getParameters()) {
+
+                if (!parameter.getSpecification().isSignature()) {
+                    builder.string(parameter.getLocalName());
+                } else {
+                    if (index < signatureParameters.size()) {
+                        ActualParameter specializationParam = signatureParameters.get(index);
+
+                        TypeData targetType = parameter.getTypeSystemType();
+                        TypeData sourceType = specializationParam.getTypeSystemType();
+                        String localName = specializationParam.getLocalName();
+                        if (unexpectedParameter != null && unexpectedParameter.getLocalName().equals(specializationParam.getLocalName())) {
+                            localName = "ex.getResult()";
+                            sourceType = getModel().getNode().getTypeSystem().getGenericTypeData();
+                        }
+
+                        CodeTree value = CodeTreeBuilder.singleString(localName);
+
+                        if (sourceType.needsCastTo(getContext(), targetType)) {
+                            value = createCallTypeSystemMethod(getContext(), builder, getModel().getNode(), TypeSystemCodeGenerator.asTypeMethodName(targetType), value);
+                        }
+                        builder.tree(value);
+                    } else {
+                        builder.defaultValue(parameter.getType());
+                    }
+                    index++;
+                }
             }
+
             builder.end();
+
             return builder.getRoot();
         }
 
-        private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, ExecutableTypeData currentExecutable, SpecializationData specialization,
-                        ActualParameter parameter, ActualParameter exceptionParam) {
+        private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ActualParameter parameter,
+                        ActualParameter exceptionParam) {
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
 
             NodeChildData forField = specialization.getNode().findChild(parameter.getSpecification().getName());
@@ -1753,7 +1815,7 @@
 
             ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter);
 
-            builder.tree(createShortCircuitValue(builder, currentExecutable, specialization, forField, shortCircuitParam, exceptionParam));
+            builder.tree(createShortCircuitValue(builder, specialization, forField, shortCircuitParam, exceptionParam));
 
             builder.declaration(parameter.getType(), targetVariableName, CodeTreeBuilder.createBuilder().defaultValue(parameter.getType()));
             builder.startIf().string(shortCircuitParam.getLocalName()).end();
@@ -1764,8 +1826,7 @@
             return builder.getRoot();
         }
 
-        private CodeTree createShortCircuitValue(CodeTreeBuilder parent, ExecutableTypeData currentExecutable, SpecializationData specialization, NodeChildData forField,
-                        ActualParameter shortCircuitParam, ActualParameter exceptionParam) {
+        private CodeTree createShortCircuitValue(CodeTreeBuilder parent, SpecializationData specialization, NodeChildData forField, ActualParameter shortCircuitParam, ActualParameter exceptionParam) {
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             int shortCircuitIndex = 0;
             for (NodeChildData field : specialization.getNode().getChildren()) {
@@ -1779,77 +1840,30 @@
 
             builder.startStatement().type(shortCircuitParam.getType()).string(" ").string(valueName(shortCircuitParam)).string(" = ");
             ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex);
-            builder.tree(createTemplateMethodCall(builder, currentExecutable, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null));
+            builder.tree(createTemplateMethodCall(builder, null, specialization, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null));
             builder.end(); // statement
 
             return builder.getRoot();
         }
 
-        private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam) {
+        private CodeTree createReturnExecuteAndSpecialize(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam) {
+
+            SpecializationData generic = nextSpecialization.getNode().getGenericSpecialization();
             CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent);
-            specializeCall.startCall("specializeAndExecute");
+            specializeCall.startCall(EXECUTE_SPECIALIZE_NAME);
             specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class");
-            addInternalValueParameterNames(specializeCall, executable, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true,
-                            true);
+            addInternalValueParameterNames(specializeCall, generic, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, true);
             specializeCall.end().end();
 
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+
             builder.startReturn();
-            builder.tree(createExpectType(nextSpecialization.getNode(), executable, specializeCall.getRoot()));
+            builder.tree(createExpectExecutableType(nextSpecialization.getNode(), generic.getReturnSignature(), executable, specializeCall.getRoot()));
             builder.end();
 
             return builder.getRoot();
         }
 
-        private void buildSpecializeAndExecute(CodeTypeElement clazz, SpecializationData specialization) {
-            NodeData node = specialization.getNode();
-            TypeData returnType = node.getGenericSpecialization().getReturnType().getTypeSystemType();
-
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), returnType.getPrimitiveType(), "specializeAndExecute");
-            method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
-            addInternalValueParameters(method, specialization.getNode().getGenericSpecialization(), true);
-            clazz.add(method);
-
-            CodeTreeBuilder builder = method.createBuilder();
-
-            builder.tree(createDeoptimize(builder));
-            emitSpecializationListeners(builder, specialization.getNode());
-
-            builder.startStatement();
-            builder.startCall("replace");
-            builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState");
-            addInternalValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), specialization.getNode().getGenericSpecialization(), null, true, true);
-            builder.end();
-            builder.end(); // call replace
-            builder.end(); // statement
-
-            String generatedMethodName;
-            if (specialization.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) {
-                generatedMethodName = generatedGenericMethodName(null);
-            } else {
-                generatedMethodName = generatedGenericMethodName(specialization.findNextSpecialization());
-            }
-            ExecutableElement generatedGeneric = clazz.getEnclosingClass().getMethod(generatedMethodName);
-
-            CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder();
-            genericExecute.startCall(factoryClassName(specialization.getNode()), generatedMethodName);
-            genericExecute.string("this");
-            addInternalValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), specialization.getNode().getGenericSpecialization(), null, true, true);
-            genericExecute.end(); // call generated generic
-
-            CodeTree genericInvocation = genericExecute.getRoot();
-
-            if (generatedGeneric != null && Utils.isVoid(generatedGeneric.getReturnType())) {
-                builder.statement(genericInvocation);
-
-                if (!Utils.isVoid(builder.findMethod().asType())) {
-                    builder.startReturn().defaultValue(returnType.getPrimitiveType()).end();
-                }
-            } else {
-                builder.startReturn().tree(genericInvocation).end();
-            }
-        }
-
     }
 
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Sun Apr 28 22:52:12 2013 +0200
@@ -224,8 +224,8 @@
         return methods;
     }
 
-    public ExecutableTypeData findGenericExecutableType(ProcessorContext context, TypeData type) {
-        List<ExecutableTypeData> types = findGenericExecutableTypes(context);
+    public ExecutableTypeData findGenericExecutableType(ProcessorContext context, TypeData type, int evaluatedCount) {
+        List<ExecutableTypeData> types = findGenericExecutableTypes(context, evaluatedCount);
         for (ExecutableTypeData availableType : types) {
             if (Utils.typeEquals(availableType.getType().getBoxedType(), type.getBoxedType())) {
                 return availableType;
@@ -234,8 +234,8 @@
         return null;
     }
 
-    public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context) {
-        List<ExecutableTypeData> types = findGenericExecutableTypes(context);
+    public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context, int evaluatedCount) {
+        List<ExecutableTypeData> types = findGenericExecutableTypes(context, evaluatedCount);
         for (ExecutableTypeData type : types) {
             if (type.getType().isGeneric()) {
                 return type;
@@ -261,13 +261,17 @@
             }
             return typeData;
         } else {
-            return executableTypes.get(evaluatedCount);
+            List<ExecutableTypeData> types = executableTypes.get(evaluatedCount);
+            if (types == null) {
+                return Collections.emptyList();
+            }
+            return types;
         }
     }
 
-    public List<ExecutableTypeData> findGenericExecutableTypes(ProcessorContext context) {
+    public List<ExecutableTypeData> findGenericExecutableTypes(ProcessorContext context, int evaluatedCount) {
         List<ExecutableTypeData> types = new ArrayList<>();
-        for (ExecutableTypeData type : getExecutableTypes(0)) {
+        for (ExecutableTypeData type : getExecutableTypes(evaluatedCount)) {
             if (!type.hasUnexpectedValue(context)) {
                 types.add(type);
             }
@@ -275,8 +279,8 @@
         return types;
     }
 
-    public ExecutableTypeData findExecutableType(TypeData prmitiveType) {
-        for (ExecutableTypeData type : getExecutableTypes(0)) {
+    public ExecutableTypeData findExecutableType(TypeData prmitiveType, int evaluatedCount) {
+        for (ExecutableTypeData type : getExecutableTypes(evaluatedCount)) {
             if (Utils.typeEquals(type.getType().getPrimitiveType(), prmitiveType.getPrimitiveType())) {
                 return type;
             }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java	Sun Apr 28 22:52:12 2013 +0200
@@ -42,7 +42,8 @@
         return template;
     }
 
-    protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData) {
+    @SuppressWarnings("unused")
+    protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData, int evaluatedCount) {
         ParameterSpec spec = new ParameterSpec(valueName, nodeTypeMirrors(nodeData));
         spec.setSignature(true);
         return spec;
@@ -61,7 +62,7 @@
     }
 
     protected ParameterSpec createReturnParameterSpec() {
-        return createValueParameterSpec("returnValue", getNode());
+        return createValueParameterSpec("returnValue", getNode(), 0);
     }
 
     @Override
@@ -95,7 +96,7 @@
         if (getNode().getChildren() != null) {
             for (NodeChildData child : getNode().getChildren()) {
                 if (child.getExecutionKind() == ExecutionKind.DEFAULT) {
-                    ParameterSpec spec = createValueParameterSpec(child.getName(), child.getNodeData());
+                    ParameterSpec spec = createValueParameterSpec(child.getName(), child.getNodeData(), child.getExecuteWith().size());
                     if (child.getCardinality().isMany()) {
                         spec.setCardinality(Cardinality.MANY);
                         spec.setIndexed(true);
@@ -110,7 +111,7 @@
                     if (shortCircuitsEnabled) {
                         methodSpec.addRequired(new ParameterSpec(shortCircuitValueName(valueName), getContext().getType(boolean.class)));
                     }
-                    methodSpec.addRequired(createValueParameterSpec(valueName, child.getNodeData()));
+                    methodSpec.addRequired(createValueParameterSpec(valueName, child.getNodeData(), child.getExecuteWith().size()));
                 } else {
                     assert false;
                 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Sun Apr 28 22:52:12 2013 +0200
@@ -310,7 +310,7 @@
             GenericParser parser = new GenericParser(context, node);
             MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, true, null);
 
-            ExecutableTypeData anyGenericReturnType = node.findAnyGenericExecutableType(context);
+            ExecutableTypeData anyGenericReturnType = node.findAnyGenericExecutableType(context, 0);
             assert anyGenericReturnType != null;
 
             ActualParameter returnType = new ActualParameter(specification.getReturnType(), anyGenericReturnType.getType(), 0, false);
@@ -322,7 +322,7 @@
                 if (child == null) {
                     actualType = specializationParameter.getTypeSystemType();
                 } else {
-                    ExecutableTypeData paramType = child.getNodeData().findAnyGenericExecutableType(context);
+                    ExecutableTypeData paramType = child.findAnyGenericExecutableType(context);
                     assert paramType != null;
                     actualType = paramType.getType();
                 }
@@ -582,11 +582,10 @@
         nodeData.setSplitByMethodName(splitByMethodName);
         nodeData.setTypeSystem(typeSystem);
         nodeData.setFields(parseFields(elements));
+        parsedNodes.put(Utils.getQualifiedName(templateType), nodeData);
+        // parseChildren invokes cyclic parsing.
+        nodeData.setChildren(parseChildren(elements, lookupTypes));
         nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements)));
-        parsedNodes.put(Utils.getQualifiedName(templateType), nodeData);
-
-        // parseChildren invokes cyclic parsing.
-        nodeData.setChildren(parseChildren(templateType, elements, lookupTypes));
 
         return nodeData;
     }
@@ -723,7 +722,7 @@
         return fields;
     }
 
-    private List<NodeChildData> parseChildren(TypeElement templateType, List<? extends Element> elements, final List<TypeElement> typeHierarchy) {
+    private List<NodeChildData> parseChildren(List<? extends Element> elements, final List<TypeElement> typeHierarchy) {
         Set<String> shortCircuits = new HashSet<>();
         for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
             AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class);
@@ -766,7 +765,7 @@
                     kind = ExecutionKind.SHORT_CIRCUIT;
                 }
 
-                NodeChildData nodeChild = new NodeChildData(templateType, childMirror, name, childType, getter, cardinality, kind);
+                NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, getter, cardinality, kind);
 
                 parsedChildren.add(nodeChild);
 
@@ -779,8 +778,6 @@
                 nodeChild.setNode(fieldNodeData);
                 if (fieldNodeData == null) {
                     nodeChild.addError("Node type '%s' is invalid or not a valid Node.", Utils.getQualifiedName(childType));
-                } else if (fieldNodeData.findGenericExecutableTypes(context).isEmpty()) {
-                    nodeChild.addError("No executable generic types found for node '%s'.", Utils.getQualifiedName(type));
                 }
             }
         }
@@ -794,6 +791,53 @@
                 encounteredNames.add(child.getName());
             }
         }
+
+        for (NodeChildData child : filteredChildren) {
+            List<String> executeWithStrings = Utils.getAnnotationValueList(String.class, child.getMessageAnnotation(), "executeWith");
+            AnnotationValue executeWithValue = Utils.getAnnotationValue(child.getMessageAnnotation(), "executeWith");
+            List<NodeChildData> executeWith = new ArrayList<>();
+            for (String executeWithString : executeWithStrings) {
+
+                if (child.getName().equals(executeWithString)) {
+                    child.addError(executeWithValue, "The child node '%s' cannot be executed with itself.", executeWithString);
+                    continue;
+                }
+
+                NodeChildData found = null;
+                boolean before = true;
+                for (NodeChildData resolveChild : filteredChildren) {
+                    if (resolveChild == child) {
+                        before = false;
+                        continue;
+                    }
+                    if (resolveChild.getName().equals(executeWithString)) {
+                        found = resolveChild;
+                        break;
+                    }
+                }
+
+                if (found == null) {
+                    child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The child node was not found.", child.getName(), executeWithString);
+                    continue;
+                } else if (!before) {
+                    child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The node %s is executed after the current node.", child.getName(), executeWithString,
+                                    executeWithString);
+                    continue;
+                }
+                executeWith.add(found);
+            }
+            child.setExecuteWith(executeWith);
+            if (child.getNodeData() == null) {
+                continue;
+            }
+
+            List<ExecutableTypeData> types = child.findGenericExecutableTypes(context);
+            if (types.isEmpty()) {
+                child.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s.", executeWith.size(), Utils.getSimpleName(child.getNodeType()));
+                continue;
+            }
+        }
+
         return filteredChildren;
     }
 
@@ -931,7 +975,7 @@
                 continue;
             }
             ExecutableTypeData found = null;
-            List<ExecutableTypeData> executableElements = field.getNodeData().findGenericExecutableTypes(context);
+            List<ExecutableTypeData> executableElements = field.findGenericExecutableTypes(context);
             for (ExecutableTypeData executable : executableElements) {
                 if (executable.getType().equalsType(parameter.getTypeSystemType())) {
                     found = executable;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Sun Apr 28 22:52:12 2013 +0200
@@ -85,14 +85,18 @@
             return true;
         }
         for (ActualParameter parameter : getParameters()) {
-            NodeChildData field = getNode().findChild(parameter.getSpecification().getName());
-            if (field == null) {
+            NodeChildData child = getNode().findChild(parameter.getSpecification().getName());
+            if (child == null) {
                 continue;
             }
-            ExecutableTypeData type = field.getNodeData().findExecutableType(parameter.getTypeSystemType());
+            ExecutableTypeData type = child.findExecutableType(context, parameter.getTypeSystemType());
             if (type.hasUnexpectedValue(context)) {
                 return true;
             }
+            if (type.getReturnType().getTypeSystemType().needsCastTo(context, parameter.getTypeSystemType())) {
+                return true;
+            }
+
         }
         return false;
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MessageContainer.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MessageContainer.java	Sun Apr 28 22:52:12 2013 +0200
@@ -34,11 +34,15 @@
     private final List<Message> messages = new ArrayList<>();
 
     public final void addWarning(String text, Object... params) {
-        getMessages().add(new Message(this, String.format(text, params), Kind.WARNING));
+        getMessages().add(new Message(null, this, String.format(text, params), Kind.WARNING));
     }
 
     public final void addError(String text, Object... params) {
-        getMessages().add(new Message(this, String.format(text, params), Kind.ERROR));
+        addError(null, text, params);
+    }
+
+    public final void addError(AnnotationValue value, String text, Object... params) {
+        getMessages().add(new Message(value, this, String.format(text, params), Kind.ERROR));
     }
 
     protected List<MessageContainer> findChildContainers() {
@@ -150,15 +154,21 @@
     public static final class Message {
 
         private final MessageContainer originalContainer;
+        private final AnnotationValue annotationValue;
         private final String text;
         private final Kind kind;
 
-        public Message(MessageContainer originalContainer, String text, Kind kind) {
+        public Message(AnnotationValue annotationValue, MessageContainer originalContainer, String text, Kind kind) {
+            this.annotationValue = annotationValue;
             this.originalContainer = originalContainer;
             this.text = text;
             this.kind = kind;
         }
 
+        public AnnotationValue getAnnotationValue() {
+            return annotationValue;
+        }
+
         public MessageContainer getOriginalContainer() {
             return originalContainer;
         }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Sun Apr 28 22:52:12 2013 +0200
@@ -206,6 +206,17 @@
         return types;
     }
 
+    public List<ActualParameter> getSignatureParameters() {
+        List<ActualParameter> types = new ArrayList<>();
+        for (ActualParameter parameter : getParameters()) {
+            if (!parameter.getSpecification().isSignature()) {
+                continue;
+            }
+            types.add(parameter);
+        }
+        return types;
+    }
+
     @Override
     public int compareTo(TemplateMethod o) {
         if (this == o) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java	Sun Apr 28 22:52:12 2013 +0200
@@ -110,13 +110,15 @@
         return Utils.typeEquals(boxedType, actualTypeData.boxedType);
     }
 
-    public boolean needsCastTo(TypeData targetType) {
+    public boolean needsCastTo(ProcessorContext context, TypeData targetType) {
         if (this.equals(targetType)) {
             return false;
         } else if (targetType.isGeneric()) {
             return false;
         } else if (targetType.isVoid()) {
             return false;
+        } else if (Utils.isAssignable(context, getPrimitiveType(), targetType.getPrimitiveType())) {
+            return false;
         }
         return true;
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java	Sun Apr 28 22:34:46 2013 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java	Sun Apr 28 22:52:12 2013 +0200
@@ -59,7 +59,7 @@
     }
 
     public TypedNode createLocal(String name) {
-        return ReadLocalNodeFactory.create(frameDescriptor.findOrAddFrameSlot(name, int.class));
+        return ReadLocalNodeFactory.create(frameDescriptor.findOrAddFrameSlot(name, FrameSlotKind.Int));
     }
 
     public TypedNode createStringLiteral(String value) {
@@ -67,7 +67,7 @@
     }
 
     public StatementNode createAssignment(String name, TypedNode right) {
-        return WriteLocalNodeFactory.create(frameDescriptor.findOrAddFrameSlot(name, int.class), right);
+        return WriteLocalNodeFactory.create(frameDescriptor.findOrAddFrameSlot(name, FrameSlotKind.Int), right);
     }
 
     public StatementNode createPrint(List<TypedNode> expressions) {
@@ -123,7 +123,7 @@
     }
 
     public StatementNode createReturn(TypedNode value) {
-        FrameSlot slot = frameDescriptor.findOrAddFrameSlot("<retval>", int.class);
+        FrameSlot slot = frameDescriptor.findOrAddFrameSlot("<retval>", FrameSlotKind.Int);
         if (returnValue == null) {
             returnValue = ReadLocalNodeFactory.create(slot);
         }
--- a/mx/commands.py	Sun Apr 28 22:34:46 2013 +0200
+++ b/mx/commands.py	Sun Apr 28 22:52:12 2013 +0200
@@ -749,7 +749,7 @@
             excludes += _find_classes_with_annotations(p, None, ['@Snippet', '@ClassSubstitution', '@Test'], includeInnerClasses=True).keys()
             excludes += p.find_classes_with_matching_source_line(None, lambda line: 'JaCoCo Exclude' in line, includeInnerClasses=True).keys()
             
-        includes = ['com.oracle.graal.*', 'com.oracle.max.*']
+        includes = ['com.oracle.graal.*']
         agentOptions = {
                         'append' : 'true' if _jacoco == 'append' else 'false',
                         'bootclasspath' : 'true',
@@ -1361,7 +1361,7 @@
             mx.add_argument('--' + c, action='store_const', dest='vmbuild', const=c, help='select the ' + c + ' build of the VM')
         mx.add_argument('--ecl', action='store_true', dest='make_eclipse_launch', help='create launch configuration for running VM execution(s) in Eclipse')
         mx.add_argument('--native-dbg', action='store', dest='native_dbg', help='Start the vm inside a debugger', metavar='<debugger>')
-        mx.add_argument('--gdb', action='store_const', const='/usr/bin/gdb --args', dest='native_dbg', help='alias for --native-dbg /usr/bin/gdb -- args')
+        mx.add_argument('--gdb', action='store_const', const='/usr/bin/gdb --args', dest='native_dbg', help='alias for --native-dbg /usr/bin/gdb --args')
 
         commands.update({
             'export': [export, '[-options] [zipfile]'],
--- a/mx/sanitycheck.py	Sun Apr 28 22:34:46 2013 +0200
+++ b/mx/sanitycheck.py	Sun Apr 28 22:52:12 2013 +0200
@@ -47,7 +47,8 @@
 }
 
 dacapoScalaSanityWarmup = {
-    'actors':     [0, 0, 2,  8, 10],
+# (tw) actors sometimes fails verification; hardly reproducible
+    'actors':     [0, 0, 0,  0,  0],
 # (lstadler) apparat was disabled due to a deadlock which I think is the benchmarks fault.
     'apparat':    [0, 0, 0,  0,  0],
     'factorie':   [0, 0, 2,  5,  5],
--- a/src/cpu/x86/vm/graalRuntime_x86.cpp	Sun Apr 28 22:34:46 2013 +0200
+++ b/src/cpu/x86/vm/graalRuntime_x86.cpp	Sun Apr 28 22:52:12 2013 +0200
@@ -811,68 +811,6 @@
   OopMapSet* oop_maps = NULL;
   switch (id) {
 
-    case new_instance_id:
-      {
-        Register klass = rdx; // Incoming
-        Register obj   = rax; // Result
-        __ set_info("new_instance", dont_gc_arguments);
-        __ enter();
-        OopMap* map = save_live_registers(sasm, 2);
-        int call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_instance), klass);
-        oop_maps = new OopMapSet();
-        oop_maps->add_gc_map(call_offset, map);
-        restore_live_registers_except_rax(sasm);
-        __ verify_oop(obj);
-        __ leave();
-        __ ret(0);
-
-        // rax,: new instance
-      }
-
-      break;
-
-    case new_array_id:
-      {
-        Register length   = rbx; // Incoming
-        Register klass    = rdx; // Incoming
-        Register obj      = rax; // Result
-
-        __ set_info("new_array", dont_gc_arguments);
-
-        __ enter();
-        OopMap* map = save_live_registers(sasm, 3);
-        int call_offset;
-        call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_array), klass, length);
-
-        oop_maps = new OopMapSet();
-        oop_maps->add_gc_map(call_offset, map);
-        restore_live_registers_except_rax(sasm);
-
-        __ verify_oop(obj);
-        __ leave();
-        __ ret(0);
-
-        // rax,: new array
-      }
-      break;
-
-    case new_multi_array_id:
-      { GraalStubFrame f(sasm, "new_multi_array", dont_gc_arguments);
-        // rax,: klass
-        // rbx,: rank
-        // rcx: address of 1st dimension
-        OopMap* map = save_live_registers(sasm, 4);
-        int call_offset = __ call_RT(rax, noreg, CAST_FROM_FN_PTR(address, new_multi_array), rax, rbx, rcx);
-
-        oop_maps = new OopMapSet();
-        oop_maps->add_gc_map(call_offset, map);
-        restore_live_registers_except_rax(sasm);
-
-        // rax,: new multi array
-        __ verify_oop(rax);
-      }
-      break;
-
     case register_finalizer_id:
       {
         __ set_info("register_finalizer", dont_gc_arguments);
--- a/src/share/vm/classfile/systemDictionary.hpp	Sun Apr 28 22:34:46 2013 +0200
+++ b/src/share/vm/classfile/systemDictionary.hpp	Sun Apr 28 22:52:12 2013 +0200
@@ -183,7 +183,7 @@
   do_klass(Long_klass,                                  java_lang_Long,                            Pre                 ) \
                                                                                                                          \
   /* Support for Graal */                                                                                                \
-  do_klass(GraalBitMap_klass,                     java_util_BitSet,                                             Opt) \
+  do_klass(BitSet_klass,                          java_util_BitSet,                                             Opt) \
   /* graal.hotspot */                                                                                                \
   do_klass(HotSpotCompilationResult_klass,        com_oracle_graal_hotspot_HotSpotCompilationResult,            Opt) \
   do_klass(HotSpotRuntimeCallTarget_klass,        com_oracle_graal_hotspot_HotSpotRuntimeCallTarget,            Opt) \
@@ -205,6 +205,7 @@
   do_klass(Assumptions_CallSiteTargetValue_klass, com_oracle_graal_api_code_Assumptions_CallSiteTargetValue,    Opt) \
   do_klass(BytecodePosition_klass,                com_oracle_graal_api_code_BytecodePosition,                   Opt) \
   do_klass(DebugInfo_klass,                       com_oracle_graal_api_code_DebugInfo,                          Opt) \
+  do_klass(RegisterSaveLayout_klass,              com_oracle_graal_api_code_RegisterSaveLayout,                 Opt) \
   do_klass(BytecodeFrame_klass,                   com_oracle_graal_api_code_BytecodeFrame,                      Opt) \
   do_klass(CompilationResult_klass,               com_oracle_graal_api_code_CompilationResult,                  Opt) \
   do_klass(CompilationResult_Call_klass,          com_oracle_graal_api_code_CompilationResult_Call,             Opt) \
--- a/src/share/vm/classfile/vmSymbols.hpp	Sun Apr 28 22:34:46 2013 +0200
+++ b/src/share/vm/classfile/vmSymbols.hpp	Sun Apr 28 22:52:12 2013 +0200
@@ -341,6 +341,7 @@
   template(com_oracle_graal_api_code_RegisterValue,                  "com/oracle/graal/api/code/RegisterValue")                       \
   template(com_oracle_graal_api_code_StackSlot,                      "com/oracle/graal/api/code/StackSlot")                           \
   template(com_oracle_graal_api_code_VirtualObject,                  "com/oracle/graal/api/code/VirtualObject")                       \
+  template(com_oracle_graal_api_code_RegisterSaveLayout,             "com/oracle/graal/api/code/RegisterSaveLayout")                  \
   template(com_oracle_graal_api_code_InvalidInstalledCodeException,  "com/oracle/graal/api/code/InvalidInstalledCodeException")       \
   template(startCompiler_name,                    "startCompiler")                                                                    \
   template(bootstrap_name,                        "bootstrap")                                                                        \
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Sun Apr 28 22:34:46 2013 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Sun Apr 28 22:52:12 2013 +0200
@@ -68,16 +68,16 @@
 
 const int MapWordBits = 64;
 
-static bool is_bit_set(oop bit_map, int i) {
-  jint extra_idx = i / MapWordBits;
-  arrayOop extra = (arrayOop) GraalBitMap::words(bit_map);
-  assert(extra_idx >= 0 && extra_idx < extra->length(), "unexpected index");
-  jlong word = ((jlong*) extra->base(T_LONG))[extra_idx];
+static bool is_bit_set(oop bitset, int i) {
+  jint words_idx = i / MapWordBits;
+  arrayOop words = (arrayOop) BitSet::words(bitset);
+  assert(words_idx >= 0 && words_idx < words->length(), "unexpected index");
+  jlong word = ((jlong*) words->base(T_LONG))[words_idx];
   return (word & (1LL << (i % MapWordBits))) != 0;
 }
 
-static int bitmap_size(oop bit_map) {
-  arrayOop arr = (arrayOop) GraalBitMap::words(bit_map);
+static int bitset_size(oop bitset) {
+  arrayOop arr = (arrayOop) BitSet::words(bitset);
   return arr->length() * MapWordBits;
 }
 
@@ -86,23 +86,24 @@
   OopMap* map = new OopMap(total_frame_size, parameter_count);
   oop register_map = (oop) DebugInfo::registerRefMap(debug_info);
   oop frame_map = (oop) DebugInfo::frameRefMap(debug_info);
+  oop callee_save_info = (oop) DebugInfo::calleeSaveInfo(debug_info);
 
   if (register_map != NULL) {
     for (jint i = 0; i < RegisterImpl::number_of_registers; i++) {
       bool is_oop = is_bit_set(register_map, i);
-      VMReg reg = get_hotspot_reg(i);
+      VMReg hotspot_reg = get_hotspot_reg(i);
       if (is_oop) {
-        map->set_oop(reg);
+        map->set_oop(hotspot_reg);
       } else {
-        map->set_value(reg);
+        map->set_value(hotspot_reg);
       }
     }
   }
 
-  for (jint i = 0; i < bitmap_size(frame_map); i++) {
+  for (jint i = 0; i < bitset_size(frame_map); i++) {
     bool is_oop = is_bit_set(frame_map, i);
     // HotSpot stack slots are 4 bytes
-    VMReg reg = VMRegImpl::stack2reg(i * 2);
+    VMReg reg = VMRegImpl::stack2reg(i * VMRegImpl::slots_per_word);
     if (is_oop) {
       map->set_oop(reg);
     } else {
@@ -110,6 +111,26 @@
     }
   }
 
+  if (callee_save_info != NULL) {
+    objArrayOop registers = (objArrayOop) RegisterSaveLayout::registers(callee_save_info);
+    arrayOop slots = (arrayOop) RegisterSaveLayout::slots(callee_save_info);
+    for (jint i = 0; i < slots->length(); i++) {
+      oop graal_reg = registers->obj_at(i);
+      jint graal_reg_number = code_Register::number(graal_reg);
+      VMReg hotspot_reg = get_hotspot_reg(graal_reg_number);
+      // HotSpot stack slots are 4 bytes
+      jint graal_slot = ((jint*) slots->base(T_INT))[i];
+      jint hotspot_slot = graal_slot * VMRegImpl::slots_per_word;
+      VMReg hotspot_slot_as_reg = VMRegImpl::stack2reg(hotspot_slot);
+      map->set_callee_saved(hotspot_slot_as_reg, hotspot_reg);
+#ifdef _LP64
+      // (copied from generate_oop_map() in c1_Runtime1_x86.cpp)
+      VMReg hotspot_slot_hi_as_reg = VMRegImpl::stack2reg(hotspot_slot + 1);
+      map->set_callee_saved(hotspot_slot_hi_as_reg, hotspot_reg->next());
+#endif
+    }
+  }
+
   return map;
 }
 
@@ -330,7 +351,7 @@
 }
 
 // constructor used to create a method
-CodeInstaller::CodeInstaller(Handle& comp_result, methodHandle method, GraalEnv::CodeInstallResult& result, nmethod*& nm, Handle installed_code, Handle triggered_deoptimizations) {
+CodeInstaller::CodeInstaller(Handle& comp_result, methodHandle method, GraalEnv::CodeInstallResult& result, CodeBlob*& cb, Handle installed_code, Handle triggered_deoptimizations) {
   GraalCompiler::initialize_buffer_blob();
   CodeBuffer buffer(JavaThread::current()->get_buffer_blob());
   jobject comp_result_obj = JNIHandles::make_local(comp_result());
@@ -347,8 +368,21 @@
   int stack_slots = _total_frame_size / HeapWordSize; // conversion to words
   GrowableArray<jlong>* leaf_graph_ids = get_leaf_graph_ids(comp_result);
 
-  result = GraalEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table,
-    GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, -1, false, leaf_graph_ids, installed_code, triggered_deoptimizations);
+  if (_stubName != NULL) {
+    char* name = strdup(java_lang_String::as_utf8_string(_stubName));
+    cb = RuntimeStub::new_runtime_stub(name,
+                                       &buffer,
+                                       CodeOffsets::frame_never_safe,
+                                       stack_slots,
+                                       _debug_recorder->_oopmaps,
+                                       false);
+    result = GraalEnv::ok;
+  } else {
+    nmethod* nm = NULL;
+    result = GraalEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table,
+        GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, -1, false, leaf_graph_ids, installed_code, triggered_deoptimizations);
+    cb = nm;
+  }
 }
 
 void CodeInstaller::initialize_fields(oop comp_result, methodHandle method) {
@@ -357,7 +391,7 @@
     _parameter_count = method->size_of_parameters();
     TRACE_graal_1("installing code for %s", method->name_and_sig_as_C_string());
   }
-  _name = HotSpotCompilationResult::name(comp_result);
+  _stubName = HotSpotCompilationResult::stubName(comp_result);
   _sites = (arrayOop) HotSpotCompilationResult::sites(comp_result);
   _exception_handlers = (arrayOop) HotSpotCompilationResult::exceptionHandlers(comp_result);
 
@@ -640,8 +674,14 @@
   if (target->is_a(SystemDictionary::HotSpotInstalledCode_klass())) {
     assert(inst->is_jump(), "jump expected");
 
-    nmethod* nm = (nmethod*) HotSpotInstalledCode::nmethod(target);
-    nativeJump_at((address)inst)->set_jump_destination(nm->verified_entry_point());
+    CodeBlob* cb = (CodeBlob*) (address) HotSpotInstalledCode::codeBlob(target);
+    assert(cb != NULL, "npe");
+    if (cb->is_nmethod()) {
+      nmethod* nm = (nmethod*) cb;
+      nativeJump_at((address)inst)->set_jump_destination(nm->verified_entry_point());
+    } else {
+      nativeJump_at((address)inst)->set_jump_destination(cb->code_begin());
+    }
     _instructions->relocate((address)inst, runtime_call_Relocation::spec(), Assembler::call32_operand);
 
     return;
--- a/src/share/vm/graal/graalCodeInstaller.hpp	Sun Apr 28 22:34:46 2013 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.hpp	Sun Apr 28 22:52:12 2013 +0200
@@ -51,7 +51,7 @@
   Arena         _arena;
 
   oop           _comp_result;
-  oop           _name;
+  oop           _stubName;
   arrayOop      _sites;
   arrayOop      _exception_handlers;
   CodeOffsets   _offsets;
@@ -76,11 +76,7 @@
 
 public:
 
-  // constructor used to create a method
-  CodeInstaller(Handle& comp_result, methodHandle method, GraalEnv::CodeInstallResult& result, nmethod*& nm, Handle installed_code, Handle triggered_deoptimizations);
-
-  // constructor used to create a stub
-  CodeInstaller(Handle& target_method, BufferBlob*& blob, jlong& id);
+  CodeInstaller(Handle& comp_result, methodHandle method, GraalEnv::CodeInstallResult& result, CodeBlob*& cb, Handle installed_code, Handle triggered_deoptimizations);
 
   static address runtime_call_target_address(oop runtime_call);
 
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Sun Apr 28 22:34:46 2013 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Sun Apr 28 22:52:12 2013 +0200
@@ -620,7 +620,7 @@
 #define set_boolean(name, value) do { env->SetBooleanField(config, getFieldID(env, config, name, "Z"), value); } while (0)
 #define set_int(name, value) do { env->SetIntField(config, getFieldID(env, config, name, "I"), value); } while (0)
 #define set_long(name, value) do { env->SetLongField(config, getFieldID(env, config, name, "J"), value); } while (0)
-#define set_stub(name, value) do { set_long(name, (jlong) value); } while (0)
+#define set_address(name, value) do { set_long(name, (jlong) value); } while (0)
 #define set_object(name, value) do { env->SetObjectField(config, getFieldID(env, config, name, "Ljava/lang/Object;"), value); } while (0)
 #define set_int_array(name, value) do { env->SetObjectField(config, getFieldID(env, config, name, "[I"), value); } while (0)
 
@@ -699,6 +699,7 @@
   set_int("arrayKlassComponentMirrorOffset", in_bytes(ArrayKlass::component_mirror_offset()));
 
 
+  set_int("pendingExceptionOffset", in_bytes(ThreadShadow::pending_exception_offset()));
   set_int("pendingDeoptimizationOffset", in_bytes(ThreadShadow::pending_deoptimization_offset()));
 
   set_int("metaspaceArrayLengthOffset", Array<Klass*>::length_offset_in_bytes());
@@ -721,6 +722,10 @@
   set_int("threadTlabStartOffset", in_bytes(JavaThread::tlab_start_offset()));
   set_int("threadTlabSizeOffset", in_bytes(JavaThread::tlab_size_offset()));
   set_int("threadAllocatedBytesOffset", in_bytes(JavaThread::allocated_bytes_offset()));
+  set_int("threadLastJavaSpOffset", in_bytes(JavaThread::last_Java_sp_offset()));
+  set_int("threadLastJavaFpOffset", in_bytes(JavaThread::last_Java_fp_offset()));
+  set_int("threadLastJavaPcOffset", in_bytes(JavaThread::last_Java_pc_offset()));
+  set_int("threadObjectResultOffset", in_bytes(JavaThread::vm_result_offset()));
   set_int("tlabSlowAllocationsOffset", in_bytes(JavaThread::tlab_slow_allocations_offset()));
   set_int("tlabFastRefillWasteOffset", in_bytes(JavaThread::tlab_fast_refill_waste_offset()));
   set_int("tlabNumberOfRefillsOffset", in_bytes(JavaThread::tlab_number_of_refills_offset()));
@@ -742,42 +747,43 @@
   set_int("layoutHelperOffset", in_bytes(Klass::layout_helper_offset()));
 
 
-  set_stub("wbPreCallStub", GraalRuntime::entry_for(GraalRuntime::wb_pre_call_id));
-  set_stub("wbPostCallStub", GraalRuntime::entry_for(GraalRuntime::wb_post_call_id));
+  set_address("wbPreCallStub", GraalRuntime::entry_for(GraalRuntime::wb_pre_call_id));
+  set_address("wbPostCallStub", GraalRuntime::entry_for(GraalRuntime::wb_post_call_id));
 
-  set_stub("newInstanceStub", GraalRuntime::entry_for(GraalRuntime::new_instance_id));
-  set_stub("newArrayStub", GraalRuntime::entry_for(GraalRuntime::new_array_id));
-  set_stub("newMultiArrayStub", GraalRuntime::entry_for(GraalRuntime::new_multi_array_id));
-  set_stub("identityHashCodeStub", GraalRuntime::entry_for(GraalRuntime::identity_hash_code_id));
-  set_stub("threadIsInterruptedStub", GraalRuntime::entry_for(GraalRuntime::thread_is_interrupted_id));
-  set_stub("inlineCacheMissStub", SharedRuntime::get_ic_miss_stub());
-  set_stub("handleExceptionStub", GraalRuntime::entry_for(GraalRuntime::handle_exception_nofpu_id));
-  set_stub("handleDeoptStub", SharedRuntime::deopt_blob()->unpack());
-  set_stub("monitorEnterStub", GraalRuntime::entry_for(GraalRuntime::monitorenter_id));
-  set_stub("monitorExitStub", GraalRuntime::entry_for(GraalRuntime::monitorexit_id));
-  set_stub("verifyOopStub", GraalRuntime::entry_for(GraalRuntime::verify_oop_id));
-  set_stub("vmErrorStub", GraalRuntime::entry_for(GraalRuntime::vm_error_id));
-  set_stub("deoptimizeStub", SharedRuntime::deopt_blob()->uncommon_trap());
-  set_stub("unwindExceptionStub", GraalRuntime::entry_for(GraalRuntime::unwind_exception_call_id));
-  set_stub("osrMigrationEndStub", GraalRuntime::entry_for(GraalRuntime::OSR_migration_end_id));
-  set_stub("registerFinalizerStub", GraalRuntime::entry_for(GraalRuntime::register_finalizer_id));
-  set_stub("createNullPointerExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_null_pointer_exception_id));
-  set_stub("createOutOfBoundsExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_out_of_bounds_exception_id));
-  set_stub("javaTimeMillisStub", CAST_FROM_FN_PTR(address, os::javaTimeMillis));
-  set_stub("javaTimeNanosStub", CAST_FROM_FN_PTR(address, os::javaTimeNanos));
-  set_stub("arithmeticFremStub", GraalRuntime::entry_for(GraalRuntime::arithmetic_frem_id));
-  set_stub("arithmeticDremStub", GraalRuntime::entry_for(GraalRuntime::arithmetic_drem_id));
-  set_stub("arithmeticSinStub", CAST_FROM_FN_PTR(address, SharedRuntime::dsin));
-  set_stub("arithmeticCosStub", CAST_FROM_FN_PTR(address, SharedRuntime::dcos));
-  set_stub("arithmeticTanStub", CAST_FROM_FN_PTR(address, SharedRuntime::dtan));
-  set_stub("logPrimitiveStub", GraalRuntime::entry_for(GraalRuntime::log_primitive_id));
-  set_stub("logObjectStub", GraalRuntime::entry_for(GraalRuntime::log_object_id));
-  set_stub("logPrintfStub", GraalRuntime::entry_for(GraalRuntime::log_printf_id));
-  set_stub("stubPrintfStub", GraalRuntime::entry_for(GraalRuntime::stub_printf_id));
-  set_stub("aescryptEncryptBlockStub", StubRoutines::aescrypt_encryptBlock());
-  set_stub("aescryptDecryptBlockStub", StubRoutines::aescrypt_decryptBlock());
-  set_stub("cipherBlockChainingEncryptAESCryptStub", StubRoutines::cipherBlockChaining_encryptAESCrypt());
-  set_stub("cipherBlockChainingDecryptAESCryptStub", StubRoutines::cipherBlockChaining_decryptAESCrypt());
+  set_address("identityHashCodeStub", GraalRuntime::entry_for(GraalRuntime::identity_hash_code_id));
+  set_address("threadIsInterruptedStub", GraalRuntime::entry_for(GraalRuntime::thread_is_interrupted_id));
+  set_address("inlineCacheMissStub", SharedRuntime::get_ic_miss_stub());
+  set_address("handleExceptionStub", GraalRuntime::entry_for(GraalRuntime::handle_exception_nofpu_id));
+  set_address("handleDeoptStub", SharedRuntime::deopt_blob()->unpack());
+  set_address("monitorEnterStub", GraalRuntime::entry_for(GraalRuntime::monitorenter_id));
+  set_address("monitorExitStub", GraalRuntime::entry_for(GraalRuntime::monitorexit_id));
+  set_address("verifyOopStub", GraalRuntime::entry_for(GraalRuntime::verify_oop_id));
+  set_address("vmErrorStub", GraalRuntime::entry_for(GraalRuntime::vm_error_id));
+  set_address("deoptimizeStub", SharedRuntime::deopt_blob()->uncommon_trap());
+  set_address("unwindExceptionStub", GraalRuntime::entry_for(GraalRuntime::unwind_exception_call_id));
+  set_address("osrMigrationEndStub", GraalRuntime::entry_for(GraalRuntime::OSR_migration_end_id));
+  set_address("registerFinalizerStub", GraalRuntime::entry_for(GraalRuntime::register_finalizer_id));
+  set_address("createNullPointerExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_null_pointer_exception_id));
+  set_address("createOutOfBoundsExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_out_of_bounds_exception_id));
+  set_address("javaTimeMillisStub", CAST_FROM_FN_PTR(address, os::javaTimeMillis));
+  set_address("javaTimeNanosStub", CAST_FROM_FN_PTR(address, os::javaTimeNanos));
+  set_address("arithmeticFremStub", GraalRuntime::entry_for(GraalRuntime::arithmetic_frem_id));
+  set_address("arithmeticDremStub", GraalRuntime::entry_for(GraalRuntime::arithmetic_drem_id));
+  set_address("arithmeticSinStub", CAST_FROM_FN_PTR(address, SharedRuntime::dsin));
+  set_address("arithmeticCosStub", CAST_FROM_FN_PTR(address, SharedRuntime::dcos));
+  set_address("arithmeticTanStub", CAST_FROM_FN_PTR(address, SharedRuntime::dtan));
+  set_address("logPrimitiveStub", GraalRuntime::entry_for(GraalRuntime::log_primitive_id));
+  set_address("logObjectStub", GraalRuntime::entry_for(GraalRuntime::log_object_id));
+  set_address("logPrintfStub", GraalRuntime::entry_for(GraalRuntime::log_printf_id));
+  set_address("stubPrintfStub", GraalRuntime::entry_for(GraalRuntime::stub_printf_id));
+  set_address("aescryptEncryptBlockStub", StubRoutines::aescrypt_encryptBlock());
+  set_address("aescryptDecryptBlockStub", StubRoutines::aescrypt_decryptBlock());
+  set_address("cipherBlockChainingEncryptAESCryptStub", StubRoutines::cipherBlockChaining_encryptAESCrypt());
+  set_address("cipherBlockChainingDecryptAESCryptStub", StubRoutines::cipherBlockChaining_decryptAESCrypt());
+
+  set_address("newInstanceAddress", GraalRuntime::new_instance);
+  set_address("newArrayAddress", GraalRuntime::new_array);
+  set_address("newMultiArrayAddress", GraalRuntime::new_multi_array);
 
   set_int("deoptReasonNone", Deoptimization::Reason_none);
   set_int("deoptReasonNullCheck", Deoptimization::Reason_null_check);
@@ -849,12 +855,13 @@
   ResourceMark rm;
   HandleMark hm;
   Handle compResultHandle = JNIHandles::resolve(compResult);
-  nmethod* nm = NULL;
+  CodeBlob* cb = NULL;
   methodHandle method = getMethodFromHotSpotMethod(HotSpotCompilationResult::method(compResult));
   Handle installed_code_handle = JNIHandles::resolve(installed_code);
   Handle triggered_deoptimizations_handle = JNIHandles::resolve(triggered_deoptimizations);
   GraalEnv::CodeInstallResult result;
-  CodeInstaller installer(compResultHandle, method, result, nm, installed_code_handle, triggered_deoptimizations_handle);
+
+  CodeInstaller installer(compResultHandle, method, result, cb, installed_code_handle, triggered_deoptimizations_handle);
 
   if (PrintCodeCacheOnCompilation) {
     stringStream s;
@@ -868,13 +875,15 @@
   }
 
   if (result != GraalEnv::ok) {
-    assert(nm == NULL, "should be");
+    assert(cb == NULL, "should be");
   } else {
     if (!installed_code_handle.is_null()) {
       assert(installed_code_handle->is_a(HotSpotInstalledCode::klass()), "wrong type");
-      HotSpotInstalledCode::set_nmethod(installed_code_handle, (jlong) nm);
+      HotSpotInstalledCode::set_codeBlob(installed_code_handle, (jlong) cb);
       HotSpotInstalledCode::set_method(installed_code_handle, HotSpotCompilationResult::method(compResult));
-      HotSpotInstalledCode::set_start(installed_code_handle, (jlong) nm->code_begin());
+      HotSpotInstalledCode::set_start(installed_code_handle, (jlong) cb->code_begin());
+      HotSpotInstalledCode::set_isNmethod(installed_code_handle, cb->is_nmethod());
+      nmethod* nm = cb->as_nmethod_or_null();
       assert(nm == NULL || !installed_code_handle->is_scavengable() || nm->on_scavenge_root_list(), "nm should be scavengable if installed_code is scavengable");
     }
   }
@@ -886,30 +895,53 @@
   method->clear_queued_for_compilation();
 C2V_END
 
-C2V_VMENTRY(jobject, getCode, (JNIEnv *jniEnv, jobject,  jlong metaspace_nmethod))
+C2V_VMENTRY(jobject, getCode, (JNIEnv *jniEnv, jobject,  jlong codeBlob))
+  ResourceMark rm;
+  HandleMark hm;
+
+  CodeBlob* cb = (CodeBlob*) (address) codeBlob;
+  if (cb == NULL) {
+    return NULL;
+  }
+  if (cb->is_nmethod()) {
+    nmethod* nm = (nmethod*) cb;
+    if (!nm->is_alive()) {
+      return NULL;
+    }
+  }
+  int length = cb->code_size();
+  arrayOop codeCopy = oopFactory::new_byteArray(length, CHECK_0);
+  memcpy(codeCopy->base(T_BYTE), cb->code_begin(), length);
+  return JNIHandles::make_local(codeCopy);
+C2V_END
+
+C2V_VMENTRY(jobject, disassembleCodeBlob, (JNIEnv *jniEnv, jobject, jlong codeBlob))
   ResourceMark rm;
   HandleMark hm;
 
-  nmethod* nm = (nmethod*) (address) metaspace_nmethod;
-  if (nm == NULL || !nm->is_alive()) {
+  CodeBlob* cb = (CodeBlob*) (address) codeBlob;
+  if (cb == NULL) {
     return NULL;
   }
-  int length = nm->code_size();
-  arrayOop codeCopy = oopFactory::new_byteArray(length, CHECK_0);
-  memcpy(codeCopy->base(T_BYTE), nm->code_begin(), length);
-  return JNIHandles::make_local(codeCopy);
-C2V_END
 
-C2V_VMENTRY(jobject, disassembleNMethod, (JNIEnv *jniEnv, jobject, jlong metaspace_nmethod))
-  ResourceMark rm;
-  HandleMark hm;
-
-  nmethod* nm = (nmethod*) (address) metaspace_nmethod;
-  if (nm == NULL || !nm->is_alive()) {
-    return NULL;
+  // We don't want the stringStream buffer to resize during disassembly as it
+  // uses scoped resource memory. If a nested function called during disassembly uses
+  // a ResourceMark and the buffer expands within the scope of the mark,
+  // the buffer becomes garbage when that scope is exited. Experience shows that
+  // the disassembled code is typically about 10x the code size so a fixed buffer
+  // sized to 20x code size should be sufficient.
+  int bufferSize = cb->code_size() * 20;
+  char* buffer = NEW_RESOURCE_ARRAY(char, bufferSize);
+  stringStream st(buffer, bufferSize);
+  if (cb->is_nmethod()) {
+    nmethod* nm = (nmethod*) cb;
+    if (!nm->is_alive()) {
+      return NULL;
+    }
+    Disassembler::decode(nm, &st);
+  } else {
+    Disassembler::decode(cb, &st);
   }
-  stringStream(st);
-  Disassembler::decode(nm, &st);
 
   Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL);
   return JNIHandles::make_local(result());
@@ -924,11 +956,11 @@
   return JNIHandles::make_local(element);
 C2V_END
 
-C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv *env, jobject, jobject args, jlong nativeMethod))
+C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv *env, jobject, jobject args, jlong nmethodValue))
   ResourceMark rm;
   HandleMark hm;
 
-  nmethod* nm = (nmethod*) (address) nativeMethod;
+  nmethod* nm = (nmethod*) (address) nmethodValue;
   methodHandle mh = nm->method();
   Symbol* signature = mh->signature();
   JavaCallArguments jca(mh->size_of_parameters());
@@ -1150,7 +1182,7 @@
   {CC"initializeConfiguration",       CC"("HS_CONFIG")V",                                               FN_PTR(initializeConfiguration)},
   {CC"installCode0",                  CC"("HS_COMP_RESULT HS_INSTALLED_CODE"[Z)I",                      FN_PTR(installCode0)},
   {CC"getCode",                       CC"(J)[B",                                                        FN_PTR(getCode)},
-  {CC"disassembleNMethod",            CC"(J)"STRING,                                                    FN_PTR(disassembleNMethod)},
+  {CC"disassembleCodeBlob",           CC"(J)"STRING,                                                    FN_PTR(disassembleCodeBlob)},
   {CC"executeCompiledMethodVarargs",  CC"(["OBJECT NMETHOD")"OBJECT,                                    FN_PTR(executeCompiledMethodVarargs)},
   {CC"getDeoptedLeafGraphIds",        CC"()[J",                                                         FN_PTR(getDeoptedLeafGraphIds)},
   {CC"getLineNumberTable",            CC"("HS_RESOLVED_METHOD")[J",                                     FN_PTR(getLineNumberTable)},
--- a/src/share/vm/graal/graalJavaAccess.cpp	Sun Apr 28 22:34:46 2013 +0200
+++ b/src/share/vm/graal/graalJavaAccess.cpp	Sun Apr 28 22:52:12 2013 +0200
@@ -32,7 +32,7 @@
   Symbol* name_symbol = SymbolTable::probe(name, (int)strlen(name));
   Symbol* signature_symbol = SymbolTable::probe(signature, (int)strlen(signature));
 #ifndef PRODUCT
-  if (name_symbol == NULL) {
+  if (name_symbol == NULL || signature_symbol == NULL) {
     tty->print_cr("symbol with name %s was not found in symbol table (klass=%s)", name, klass->name()->as_C_string());
   }
 #endif
--- a/src/share/vm/graal/graalJavaAccess.hpp	Sun Apr 28 22:34:46 2013 +0200
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Sun Apr 28 22:52:12 2013 +0200
@@ -73,15 +73,16 @@
     int_field(HotSpotResolvedJavaField, flags)                                                                                                                 \
   end_class                                                                                                                                                    \
   start_class(HotSpotInstalledCode)                                                                                                                            \
-    long_field(HotSpotInstalledCode, nmethod)                                                                                                                  \
+    long_field(HotSpotInstalledCode, codeBlob)                                                                                                                 \
     oop_field(HotSpotInstalledCode, method, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;")                                                       \
     long_field(HotSpotInstalledCode, start)                                                                                                                    \
     boolean_field(HotSpotInstalledCode, isDefault)                                                                                                             \
+    boolean_field(HotSpotInstalledCode, isNmethod)                                                                                                             \
   end_class                                                                                                                                                    \
   start_class(HotSpotCompilationResult)                                                                                                                        \
     oop_field(HotSpotCompilationResult, comp, "Lcom/oracle/graal/api/code/CompilationResult;")                                                                 \
     oop_field(HotSpotCompilationResult, method, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;")                                                   \
-    oop_field(HotSpotCompilationResult, name, "Ljava/lang/String;")                                                                                            \
+    oop_field(HotSpotCompilationResult, stubName, "Ljava/lang/String;")                                                                                        \
     int_field(HotSpotCompilationResult, entryBCI)                                                                                                              \
     oop_field(HotSpotCompilationResult, sites, "[Lcom/oracle/graal/api/code/CompilationResult$Site;")                                                          \
     oop_field(HotSpotCompilationResult, exceptionHandlers, "[Lcom/oracle/graal/api/code/CompilationResult$ExceptionHandler;")                                  \
@@ -162,9 +163,14 @@
     oop_field(DebugInfo, bytecodePosition, "Lcom/oracle/graal/api/code/BytecodePosition;")                                                                     \
     oop_field(DebugInfo, registerRefMap, "Ljava/util/BitSet;")                                                                                                 \
     oop_field(DebugInfo, frameRefMap, "Ljava/util/BitSet;")                                                                                                    \
+    oop_field(DebugInfo, calleeSaveInfo, "Lcom/oracle/graal/api/code/RegisterSaveLayout;")                                                                     \
   end_class                                                                                                                                                    \
-  start_class(GraalBitMap)                                                                                                                                     \
-    oop_field(GraalBitMap, words, "[J")                                                                                                                        \
+  start_class(RegisterSaveLayout)                                                                                                                              \
+    oop_field(RegisterSaveLayout, registers, "[Lcom/oracle/graal/api/code/Register;")                                                                          \
+    oop_field(RegisterSaveLayout, slots, "[I")                                                                                                                 \
+  end_class                                                                                                                                                    \
+  start_class(BitSet)                                                                                                                                          \
+    oop_field(BitSet, words, "[J")                                                                                                                             \
   end_class                                                                                                                                                    \
   start_class(BytecodeFrame)                                                                                                                                   \
     oop_field(BytecodeFrame, values, "[Lcom/oracle/graal/api/meta/Value;")                                                                                     \
@@ -197,7 +203,7 @@
   end_class                                                                                                                                                    \
   start_class(Value)                                                                                                                                           \
     oop_field(Value, kind, "Lcom/oracle/graal/api/meta/Kind;")                                                                                                 \
-    static_oop_field(Value, ILLEGAL, "Lcom/oracle/graal/api/meta/Value;");                                                                                     \
+    static_oop_field(Value, ILLEGAL, "Lcom/oracle/graal/api/meta/AllocatableValue;");                                                                          \
   end_class                                                                                                                                                    \
   start_class(RegisterValue)                                                                                                                                   \
     oop_field(RegisterValue, reg, "Lcom/oracle/graal/api/code/Register;")                                                                                      \
--- a/src/share/vm/graal/graalRuntime.cpp	Sun Apr 28 22:34:46 2013 +0200
+++ b/src/share/vm/graal/graalRuntime.cpp	Sun Apr 28 22:52:12 2013 +0200
@@ -260,11 +260,16 @@
   // This is pretty rare but this runtime patch is stressful to deoptimization
   // if we deoptimize here so force a deopt to stress the path.
   if (DeoptimizeALot) {
-    deopt_caller();
+    static int deopts = 0;
+    // Alternate between deoptimizing and raising an error (which will also cause a deopt)
+    if (deopts++ % 2 == 0) {
+      ResourceMark rm(THREAD);
+      THROW(vmSymbols::java_lang_OutOfMemoryError());
+    } else {
+      deopt_caller();
+    }
   }
- JRT_END
-
-
+JRT_END
 
 JRT_ENTRY(void, GraalRuntime::new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims))
   assert(klass->is_klass(), "not a class");
--- a/src/share/vm/graal/graalRuntime.hpp	Sun Apr 28 22:34:46 2013 +0200
+++ b/src/share/vm/graal/graalRuntime.hpp	Sun Apr 28 22:52:12 2013 +0200
@@ -82,9 +82,6 @@
 // by Graal.
 #define GRAAL_STUBS(stub, last_entry) \
   stub(register_finalizer)      \
-  stub(new_instance)            \
-  stub(new_array)               \
-  stub(new_multi_array)         \
   stub(handle_exception_nofpu) /* optimized version that does not preserve fpu registers */ \
   stub(unwind_exception_call)   \
   stub(OSR_migration_end)       \
@@ -133,10 +130,6 @@
                                        Register arg1 = noreg, Register arg2 = noreg, Register arg3 = noreg);
 
   // runtime entry points
-  static void new_instance(JavaThread* thread, Klass* klass);
-  static void new_array(JavaThread* thread, Klass* klass, jint length);
-  static void new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims);
-
   static void unimplemented_entry(JavaThread* thread, StubID id);
 
   static address exception_handler_for_pc(JavaThread* thread);
@@ -164,6 +157,9 @@
   static void log_object(JavaThread* thread, oop msg, jint flags);
 
  public:
+  static void new_instance(JavaThread* thread, Klass* klass);
+  static void new_array(JavaThread* thread, Klass* klass, jint length);
+  static void new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims);
   // initialization
   static void initialize(BufferBlob* blob);