changeset 13934:f4dedec9b225

Merge
author Tom Rodriguez <tom.rodriguez@oracle.com>
date Tue, 11 Feb 2014 15:07:50 -0800
parents ebd2dfc2b780 (diff) c4e5a685c6a1 (current diff)
children ca0e1af320f6 e79579c921ff
files
diffstat 12 files changed, 410 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java	Tue Feb 11 22:41:50 2014 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java	Tue Feb 11 15:07:50 2014 -0800
@@ -116,6 +116,26 @@
         this.numStack = numStack;
         this.numLocks = numLocks;
         assert !rethrowException || numStack == 1 : "must have exception on top of the stack";
+        assert validateFormat();
+    }
+
+    /**
+     * Ensure that the frame state is formatted as expected by the JVM, with null or Illegal in the
+     * slot following a double word item. This should really be checked in FrameState itself but
+     * because of Word type rewriting that can't be done. If a frame makes it into this code, then
+     * could be materialized by the JVM so it must follow the rules. it
+     */
+    private boolean validateFormat() {
+        for (int i = 0; i < numLocals + numStack; i++) {
+            if (values[i] != null) {
+                Kind kind = values[i].getKind();
+                if (kind == Kind.Long || kind == Kind.Double) {
+                    assert values.length > i + 1 : String.format("missing second word %s", this);
+                    assert values[i + 1] == null || values[i + 1].getKind() == Kind.Illegal;
+                }
+            }
+        }
+        return true;
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Feb 11 22:41:50 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Feb 11 15:07:50 2014 -0800
@@ -1026,6 +1026,8 @@
     @HotSpotVMConstant(name = "JVM_CONSTANT_MethodType") @Stable public int jvmConstantMethodType;
     @HotSpotVMConstant(name = "JVM_CONSTANT_MethodTypeInError") @Stable public int jvmConstantMethodTypeInError;
 
+    @HotSpotVMConstant(name = "HeapWordSize") @Stable public int heapWordSize;
+
     @HotSpotVMField(name = "Symbol::_length", type = "unsigned short", get = HotSpotVMField.Type.OFFSET) @Stable public int symbolLengthOffset;
     @HotSpotVMField(name = "Symbol::_body[0]", type = "jbyte", get = HotSpotVMField.Type.OFFSET) @Stable public int symbolBodyOffset;
 
@@ -1282,6 +1284,35 @@
     @HotSpotVMField(name = "StubRoutines::_updateBytesCRC32", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long updateBytesCRC32Stub;
     @HotSpotVMField(name = "StubRoutines::_crc_table_adr", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long crcTableAddress;
 
+    @HotSpotVMField(name = "StubRoutines::_jbyte_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_jshort_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_jint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_jlong_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_oop_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_oop_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopArraycopyUninit;
+    @HotSpotVMField(name = "StubRoutines::_jbyte_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteDisjointArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_jshort_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortDisjointArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_jint_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintDisjointArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_jlong_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongDisjointArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_oop_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopDisjointArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_oop_disjoint_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopDisjointArraycopyUninit;
+    @HotSpotVMField(name = "StubRoutines::_arrayof_jbyte_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteAlignedArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_arrayof_jshort_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortAlignedArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_arrayof_jint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintAlignedArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_arrayof_jlong_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongAlignedArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_arrayof_oop_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long alignedOopAlignedArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_arrayof_oop_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long alignedOopArraycopyUninit;
+    @HotSpotVMField(name = "StubRoutines::_arrayof_jbyte_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteAlignedDisjointArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_arrayof_jshort_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortAlignedDisjointArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_arrayof_jint_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintAlignedDisjointArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_arrayof_jlong_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongAlignedDisjointArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_arrayof_oop_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long alignedOopDisjointArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long alignedOopDisjointArraycopyUninit;
+    @HotSpotVMField(name = "StubRoutines::_checkcast_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long checkcastArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_checkcast_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long checkcastArraycopyUninit;
+    @HotSpotVMField(name = "StubRoutines::_unsafe_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long unsafeArraycopy;
+    @HotSpotVMField(name = "StubRoutines::_generic_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long genericArraycopy;
+
     @Stable public long newInstanceAddress;
     @Stable public long newArrayAddress;
     @Stable public long newMultiArrayAddress;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Tue Feb 11 22:41:50 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Tue Feb 11 15:07:50 2014 -0800
@@ -51,6 +51,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.hotspot.stubs.*;
 
 /**
@@ -66,6 +67,14 @@
         stub.getLinkage().setCompiledStub(stub);
     }
 
+    private void registerArrayCopy(Kind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine) {
+        LocationIdentity killed = NamedLocationIdentity.getArrayLocation(kind);
+        registerForeignCall(ArrayCopySnippets.lookupArraycopyDescriptor(kind, false, false), routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
+        registerForeignCall(ArrayCopySnippets.lookupArraycopyDescriptor(kind, true, false), alignedRoutine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
+        registerForeignCall(ArrayCopySnippets.lookupArraycopyDescriptor(kind, false, true), disjointRoutine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
+        registerForeignCall(ArrayCopySnippets.lookupArraycopyDescriptor(kind, true, true), alignedDisjointRoutine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
+    }
+
     public void initialize(HotSpotProviders providers, HotSpotVMConfig c) {
         TargetDescription target = providers.getCodeCache().getTarget();
 
@@ -110,5 +119,15 @@
         linkForeignCall(providers, G1WBPRECALL, c.writeBarrierPreAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(providers, G1WBPOSTCALL, c.writeBarrierPostAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(providers, VALIDATE_OBJECT, c.validateObject, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
+
+        registerArrayCopy(Kind.Byte, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Boolean, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Char, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Short, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Int, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Float, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Long, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy);
+        registerArrayCopy(Kind.Double, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy);
+
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java	Tue Feb 11 22:41:50 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java	Tue Feb 11 15:07:50 2014 -0800
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.replacements;
 
 import static com.oracle.graal.compiler.GraalCompiler.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
@@ -63,6 +64,10 @@
         return arguments.get(4);
     }
 
+    private static boolean isHeapWordAligned(Constant value, Kind kind) {
+        return (arrayBaseOffset(kind) + value.asInt() * arrayIndexScale(kind)) % heapWordSize() == 0;
+    }
+
     private StructuredGraph selectSnippet(LoweringTool tool, final Replacements replacements) {
         ResolvedJavaType srcType = ObjectStamp.typeOrNull(getSource().stamp());
         ResolvedJavaType destType = ObjectStamp.typeOrNull(getDestination().stamp());
@@ -74,7 +79,23 @@
             return null;
         }
         Kind componentKind = srcType.getComponentType().getKind();
-        final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind));
+        boolean disjoint = false;
+        boolean aligned = false;
+        if (getSourcePosition() == getDestinationPosition()) {
+            // Can treat as disjoint
+            disjoint = true;
+        }
+        Constant constantSrc = getSourcePosition().stamp().asConstant();
+        Constant constantDst = getDestinationPosition().stamp().asConstant();
+        if (constantSrc != null && constantDst != null) {
+            aligned = isHeapWordAligned(constantSrc, componentKind) && isHeapWordAligned(constantDst, componentKind);
+            if (constantSrc.asInt() >= constantDst.asInt()) {
+                // low to high copy so treat as disjoint
+                disjoint = true;
+            }
+        }
+
+        final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind, aligned, disjoint));
         try (Scope s = Debug.scope("ArrayCopySnippet", snippetMethod)) {
             return replacements.getSnippet(snippetMethod);
         } catch (Throwable e) {
@@ -188,4 +209,5 @@
             }
         }
     }
+
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java	Tue Feb 11 22:41:50 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java	Tue Feb 11 15:07:50 2014 -0800
@@ -35,6 +35,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -51,13 +52,47 @@
 public class ArrayCopySnippets implements Snippets {
 
     private static final EnumMap<Kind, Method> arraycopyMethods = new EnumMap<>(Kind.class);
+    private static final EnumMap[][] arraycopyCalls = new EnumMap[2][2];
+    private static final EnumMap[][] arraycopyDescriptors = new EnumMap[2][2];
+
     public static final Method genericArraycopySnippet;
 
+    @SuppressWarnings("unchecked")
+    private static void findArraycopyCall(Kind kind, Class<?> arrayClass, boolean aligned, boolean disjoint) throws NoSuchMethodException {
+        String name = kind + (aligned ? "Aligned" : "") + (disjoint ? "Disjoint" : "") + "Arraycopy";
+        arraycopyCalls[aligned ? 1 : 0][disjoint ? 1 : 0].put(kind, ArrayCopySnippets.class.getDeclaredMethod(name, arrayClass, int.class, arrayClass, int.class, int.class));
+        arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].put(kind, new ForeignCallDescriptor(name, void.class, Word.class, Word.class, Word.class));
+    }
+
+    private static Method lookupArraycopyCall(Kind kind, boolean aligned, boolean disjoint) {
+        return (Method) arraycopyCalls[aligned ? 1 : 0][disjoint ? 1 : 0].get(kind);
+    }
+
+    @Fold
+    public static ForeignCallDescriptor lookupArraycopyDescriptor(Kind kind, boolean aligned, boolean disjoint) {
+        return (ForeignCallDescriptor) arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].get(kind);
+    }
+
     private static void addArraycopySnippetMethod(Kind kind, Class<?> arrayClass) throws NoSuchMethodException {
         arraycopyMethods.put(kind, ArrayCopySnippets.class.getDeclaredMethod("arraycopy", arrayClass, int.class, arrayClass, int.class, int.class));
+        if (CallArrayCopy.getValue()) {
+            if (kind != Kind.Object) {
+                // Only primitive types are currently supported
+                findArraycopyCall(kind, arrayClass, false, false);
+                findArraycopyCall(kind, arrayClass, false, true);
+                findArraycopyCall(kind, arrayClass, true, false);
+                findArraycopyCall(kind, arrayClass, true, true);
+            }
+        }
     }
 
     static {
+        for (int i = 0; i < arraycopyCalls.length; i++) {
+            for (int j = 0; j < arraycopyCalls[i].length; j++) {
+                arraycopyCalls[i][j] = new EnumMap<Kind, Method>(Kind.class);
+                arraycopyDescriptors[i][j] = new EnumMap<Kind, ForeignCallDescriptor>(Kind.class);
+            }
+        }
         try {
             addArraycopySnippetMethod(Kind.Byte, byte[].class);
             addArraycopySnippetMethod(Kind.Boolean, boolean[].class);
@@ -74,7 +109,11 @@
         }
     }
 
-    public static Method getSnippetForKind(Kind kind) {
+    public static Method getSnippetForKind(Kind kind, boolean aligned, boolean disjoint) {
+        Method m = lookupArraycopyCall(kind, aligned, disjoint);
+        if (m != null) {
+            return m;
+        }
         return arraycopyMethods.get(kind);
     }
 
@@ -195,6 +234,186 @@
         }
     }
 
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void callArraycopy(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word src, Word dst, Word len);
+
+    private static Word computeBase(Object object, Kind kind, int pos) {
+        // In this code pos must be cast to long before being multiplied since shifting the value
+        // could be outside the range of int. arrayIndexScale should probably either return long or
+        // Word to force the right thing to happen.
+        return Word.unsigned(GetObjectAddressNode.get(object) + arrayBaseOffset(kind) + (long) pos * arrayIndexScale(kind));
+    }
+
+    private static void callArraycopyTemplate(SnippetCounter counter, Kind kind, boolean aligned, boolean disjoint, Object src, int srcPos, Object dest, int destPos, int length) {
+        counter.inc();
+        Object nonNullSrc = guardingNonNull(src);
+        Object nonNullDest = guardingNonNull(dest);
+        checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length);
+        Word srcAddr = computeBase(src, kind, srcPos);
+        Word destAddr = computeBase(dest, kind, destPos);
+        callArraycopy(lookupArraycopyDescriptor(kind, aligned, disjoint), srcAddr, destAddr, Word.signed(length));
+    }
+
+    @Snippet
+    public static void byteArraycopy(byte[] src, int srcPos, byte[] dest, int destPos, int length) {
+        callArraycopyTemplate(byteCallCounter, Kind.Byte, false, false, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void byteDisjointArraycopy(byte[] src, int srcPos, byte[] dest, int destPos, int length) {
+        callArraycopyTemplate(byteDisjointCallCounter, Kind.Byte, false, true, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void byteAlignedArraycopy(byte[] src, int srcPos, byte[] dest, int destPos, int length) {
+        callArraycopyTemplate(byteAlignedCallCounter, Kind.Byte, true, false, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void byteAlignedDisjointArraycopy(byte[] src, int srcPos, byte[] dest, int destPos, int length) {
+        callArraycopyTemplate(byteAlignedDisjointCallCounter, Kind.Byte, true, true, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void booleanArraycopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) {
+        callArraycopyTemplate(booleanCallCounter, Kind.Boolean, false, false, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void booleanDisjointArraycopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) {
+        callArraycopyTemplate(booleanDisjointCallCounter, Kind.Boolean, false, true, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void booleanAlignedArraycopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) {
+        callArraycopyTemplate(booleanAlignedCallCounter, Kind.Boolean, true, false, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void booleanAlignedDisjointArraycopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) {
+        callArraycopyTemplate(booleanAlignedDisjointCallCounter, Kind.Boolean, true, true, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void charArraycopy(char[] src, int srcPos, char[] dest, int destPos, int length) {
+        callArraycopyTemplate(charCallCounter, Kind.Char, false, false, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void charDisjointArraycopy(char[] src, int srcPos, char[] dest, int destPos, int length) {
+        callArraycopyTemplate(charDisjointCallCounter, Kind.Char, false, true, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void charAlignedArraycopy(char[] src, int srcPos, char[] dest, int destPos, int length) {
+        callArraycopyTemplate(charAlignedCallCounter, Kind.Char, true, false, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void charAlignedDisjointArraycopy(char[] src, int srcPos, char[] dest, int destPos, int length) {
+        callArraycopyTemplate(charAlignedDisjointCallCounter, Kind.Char, true, true, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void shortArraycopy(short[] src, int srcPos, short[] dest, int destPos, int length) {
+        callArraycopyTemplate(shortCallCounter, Kind.Short, false, false, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void shortDisjointArraycopy(short[] src, int srcPos, short[] dest, int destPos, int length) {
+        callArraycopyTemplate(shortDisjointCallCounter, Kind.Short, false, true, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void shortAlignedArraycopy(short[] src, int srcPos, short[] dest, int destPos, int length) {
+        callArraycopyTemplate(shortAlignedCallCounter, Kind.Short, true, false, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void shortAlignedDisjointArraycopy(short[] src, int srcPos, short[] dest, int destPos, int length) {
+        callArraycopyTemplate(shortAlignedDisjointCallCounter, Kind.Short, true, true, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void intArraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) {
+        callArraycopyTemplate(intCallCounter, Kind.Int, false, false, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void intDisjointArraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) {
+        callArraycopyTemplate(intDisjointCallCounter, Kind.Int, false, true, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void intAlignedArraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) {
+        callArraycopyTemplate(intAlignedCallCounter, Kind.Int, true, false, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void intAlignedDisjointArraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) {
+        callArraycopyTemplate(intAlignedDisjointCallCounter, Kind.Int, true, true, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void floatArraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) {
+        callArraycopyTemplate(floatCallCounter, Kind.Float, false, false, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void floatDisjointArraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) {
+        callArraycopyTemplate(floatDisjointCallCounter, Kind.Float, false, true, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void floatAlignedArraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) {
+        callArraycopyTemplate(floatAlignedCallCounter, Kind.Float, true, false, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void floatAlignedDisjointArraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) {
+        callArraycopyTemplate(floatAlignedDisjointCallCounter, Kind.Float, true, true, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void longArraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) {
+        callArraycopyTemplate(longCallCounter, Kind.Long, false, false, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void longDisjointArraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) {
+        callArraycopyTemplate(longDisjointCallCounter, Kind.Long, false, true, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void longAlignedArraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) {
+        callArraycopyTemplate(longAlignedCallCounter, Kind.Long, true, false, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void longAlignedDisjointArraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) {
+        callArraycopyTemplate(longAlignedDisjointCallCounter, Kind.Long, true, true, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void doubleArraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) {
+        callArraycopyTemplate(doubleCallCounter, Kind.Double, false, false, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void doubleDisjointArraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) {
+        callArraycopyTemplate(doubleDisjointCallCounter, Kind.Double, false, true, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void doubleAlignedArraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) {
+        callArraycopyTemplate(doubleAlignedCallCounter, Kind.Double, true, false, src, srcPos, dest, destPos, length);
+    }
+
+    @Snippet
+    public static void doubleAlignedDisjointArraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) {
+        callArraycopyTemplate(doubleAlignedDisjointCallCounter, Kind.Double, true, true, src, srcPos, dest, destPos, length);
+    }
+
     private static final SnippetCounter.Group checkCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy checkInputs") : null;
     private static final SnippetCounter checkSuccessCounter = new SnippetCounter(checkCounters, "checkSuccess", "checkSuccess");
     private static final SnippetCounter checkNPECounter = new SnippetCounter(checkCounters, "checkNPE", "checkNPE");
@@ -210,6 +429,40 @@
     private static final SnippetCounter objectCounter = new SnippetCounter(counters, "Object[]", "arraycopy for Object[] arrays");
     private static final SnippetCounter floatCounter = new SnippetCounter(counters, "float[]", "arraycopy for float[] arrays");
     private static final SnippetCounter doubleCounter = new SnippetCounter(counters, "double[]", "arraycopy for double[] arrays");
+
+    private static final SnippetCounter booleanAlignedCallCounter = new SnippetCounter(counters, "boolean[]", "aligned arraycopy call for boolean[] arrays");
+    private static final SnippetCounter booleanAlignedDisjointCallCounter = new SnippetCounter(counters, "boolean[]", "aligned disjoint arraycopy call for boolean[] arrays");
+    private static final SnippetCounter booleanCallCounter = new SnippetCounter(counters, "boolean[]", "arraycopy call for boolean[] arrays");
+    private static final SnippetCounter booleanDisjointCallCounter = new SnippetCounter(counters, "boolean[]", "disjoint arraycopy call for boolean[] arrays");
+    private static final SnippetCounter byteAlignedCallCounter = new SnippetCounter(counters, "byte[]", "aligned arraycopy call for byte[] arrays");
+    private static final SnippetCounter byteAlignedDisjointCallCounter = new SnippetCounter(counters, "byte[]", "aligned disjoint arraycopy call for byte[] arrays");
+    private static final SnippetCounter byteCallCounter = new SnippetCounter(counters, "byte[]", "arraycopy call for byte[] arrays");
+    private static final SnippetCounter byteDisjointCallCounter = new SnippetCounter(counters, "byte[]", "disjoint arraycopy call for byte[] arrays");
+    private static final SnippetCounter charAlignedCallCounter = new SnippetCounter(counters, "char[]", "aligned arraycopy call for char[] arrays");
+    private static final SnippetCounter charAlignedDisjointCallCounter = new SnippetCounter(counters, "char[]", "aligned disjoint arraycopy call for char[] arrays");
+    private static final SnippetCounter charCallCounter = new SnippetCounter(counters, "char[]", "arraycopy call for char[] arrays");
+    private static final SnippetCounter charDisjointCallCounter = new SnippetCounter(counters, "char[]", "disjoint arraycopy call for char[] arrays");
+    private static final SnippetCounter doubleAlignedCallCounter = new SnippetCounter(counters, "double[]", "aligned arraycopy call for double[] arrays");
+    private static final SnippetCounter doubleAlignedDisjointCallCounter = new SnippetCounter(counters, "double[]", "aligned disjoint arraycopy call for double[] arrays");
+    private static final SnippetCounter doubleCallCounter = new SnippetCounter(counters, "double[]", "arraycopy call for double[] arrays");
+    private static final SnippetCounter doubleDisjointCallCounter = new SnippetCounter(counters, "double[]", "disjoint arraycopy call for double[] arrays");
+    private static final SnippetCounter floatAlignedCallCounter = new SnippetCounter(counters, "float[]", "aligned arraycopy call for float[] arrays");
+    private static final SnippetCounter floatAlignedDisjointCallCounter = new SnippetCounter(counters, "float[]", "aligned disjoint arraycopy call for float[] arrays");
+    private static final SnippetCounter floatCallCounter = new SnippetCounter(counters, "float[]", "arraycopy call for float[] arrays");
+    private static final SnippetCounter floatDisjointCallCounter = new SnippetCounter(counters, "float[]", "disjoint arraycopy call for float[] arrays");
+    private static final SnippetCounter intAlignedCallCounter = new SnippetCounter(counters, "int[]", "aligned arraycopy call for int[] arrays");
+    private static final SnippetCounter intAlignedDisjointCallCounter = new SnippetCounter(counters, "int[]", "aligned disjoint arraycopy call for int[] arrays");
+    private static final SnippetCounter intCallCounter = new SnippetCounter(counters, "int[]", "arraycopy call for int[] arrays");
+    private static final SnippetCounter intDisjointCallCounter = new SnippetCounter(counters, "int[]", "disjoint arraycopy call for int[] arrays");
+    private static final SnippetCounter longAlignedCallCounter = new SnippetCounter(counters, "long[]", "aligned arraycopy call for long[] arrays");
+    private static final SnippetCounter longAlignedDisjointCallCounter = new SnippetCounter(counters, "long[]", "aligned disjoint arraycopy call for long[] arrays");
+    private static final SnippetCounter longCallCounter = new SnippetCounter(counters, "long[]", "arraycopy call for long[] arrays");
+    private static final SnippetCounter longDisjointCallCounter = new SnippetCounter(counters, "long[]", "disjoint arraycopy call for long[] arrays");
+    private static final SnippetCounter shortAlignedCallCounter = new SnippetCounter(counters, "short[]", "aligned arraycopy call for short[] arrays");
+    private static final SnippetCounter shortAlignedDisjointCallCounter = new SnippetCounter(counters, "short[]", "aligned disjoint arraycopy call for short[] arrays");
+    private static final SnippetCounter shortCallCounter = new SnippetCounter(counters, "short[]", "arraycopy call for short[] arrays");
+    private static final SnippetCounter shortDisjointCallCounter = new SnippetCounter(counters, "short[]", "disjoint arraycopy call for short[] arrays");
+
     private static final SnippetCounter genericPrimitiveCallCounter = new SnippetCounter(counters, "genericPrimitive", "generic arraycopy snippet for primitive arrays");
     private static final SnippetCounter genericObjectExactCallCounter = new SnippetCounter(counters, "genericObjectExact", "generic arraycopy snippet for special object arrays");
     private static final SnippetCounter genericObjectCallCounter = new SnippetCounter(counters, "genericObject", "call to the generic, native arraycopy method");
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Tue Feb 11 22:41:50 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Tue Feb 11 15:07:50 2014 -0800
@@ -211,6 +211,11 @@
         return Unsafe.getUnsafe().pageSize();
     }
 
+    @Fold
+    public static int heapWordSize() {
+        return config().heapWordSize;
+    }
+
     public static final LocationIdentity PROTOTYPE_MARK_WORD_LOCATION = new NamedLocationIdentity("PrototypeMarkWord");
 
     @Fold
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Tue Feb 11 22:41:50 2014 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Tue Feb 11 15:07:50 2014 -0800
@@ -73,12 +73,23 @@
                 default:   throw GraalInternalError.shouldNotReachHere();
             }
         } else if (isConstant(y)) {
+            boolean isZero = ((Constant) y).isDefaultForKind();
             switch (opcode) {
-                case ICMP: masm.cmpl(asIntReg(x), crb.asIntConst(y)); break;
-                case LCMP: masm.cmpq(asLongReg(x), crb.asIntConst(y)); break;
+                case ICMP: if (isZero) {
+                    masm.testl(asIntReg(x), asIntReg(x));
+                } else {
+                    masm.cmpl(asIntReg(x), crb.asIntConst(y));
+                }
+                break;
+                case LCMP: if (isZero) {
+                    masm.testq(asLongReg(x), asLongReg(x));
+                } else {
+                    masm.cmpq(asLongReg(x), crb.asIntConst(y));
+                }
+                break;
                 case ACMP:
-                    if (((Constant) y).isNull()) {
-                        masm.cmpq(asObjectReg(x), 0); break;
+                    if (isZero) {
+                        masm.testq(asObjectReg(x), asObjectReg(x)); break;
                     } else {
                         throw GraalInternalError.shouldNotReachHere("Only null object constants are allowed in comparisons");
                     }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Tue Feb 11 22:41:50 2014 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Tue Feb 11 15:07:50 2014 -0800
@@ -139,6 +139,8 @@
         public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
             switch (kind) {
                 case Boolean:
+                    masm.movzbl(asRegister(result), address.toAddress());
+                    break;
                 case Byte:
                     masm.movsbl(asRegister(result), address.toAddress());
                     break;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Tue Feb 11 22:41:50 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Tue Feb 11 15:07:50 2014 -0800
@@ -71,7 +71,7 @@
     public static ValueNode canonicalizeRead(ValueNode read, LocationNode location, ValueNode object, CanonicalizerTool tool, boolean compressible) {
         MetaAccessProvider metaAccess = tool.getMetaAccess();
         if (read.usages().isEmpty()) {
-            // Read without usages can be savely removed.
+            // Read without usages can be safely removed.
             return null;
         }
         if (tool.canonicalizeReads() && metaAccess != null && object != null && object.isConstant()) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Tue Feb 11 22:41:50 2014 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Tue Feb 11 15:07:50 2014 -0800
@@ -232,6 +232,9 @@
     @Option(help = "Try to avoid emitting code where patching is required")
     public static final OptionValue<Boolean> ImmutableCode = new OptionValue<>(false);
 
+    @Option(help = "")
+    public static final OptionValue<Boolean> CallArrayCopy = new OptionValue<>(true);
+
     // Runtime settings
     @Option(help = "")
     public static final OptionValue<Boolean> SupportJsrBytecodes = new OptionValue<>(true);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Feb 11 22:41:50 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Feb 11 15:07:50 2014 -0800
@@ -526,8 +526,10 @@
                 ParameterNode[] params = new ParameterNode[length];
                 Stamp stamp = varargs.stamp;
                 for (int j = 0; j < length; j++) {
-                    assert (parameterCount & 0xFFFF) == parameterCount;
-                    int idx = i << 16 | j;
+                    // Use a decimal friendly numbering make it more obvious how values map
+                    assert parameterCount < 10000;
+                    int idx = (i + 1) * 10000 + j;
+                    assert idx >= parameterCount : "collision in parameter numbering";
                     ParameterNode local = snippetCopy.unique(new ParameterNode(idx, stamp));
                     params[j] = local;
                 }
@@ -542,6 +544,11 @@
                         LoadSnippetVarargParameterNode loadSnippetParameter = snippetCopy.add(new LoadSnippetVarargParameterNode(params, loadIndexed.index(), loadIndexed.stamp()));
                         snippetCopy.replaceFixedWithFixed(loadIndexed, loadSnippetParameter);
                         Debug.dump(snippetCopy, "After replacing %s", loadIndexed);
+                    } else if (usage instanceof StoreIndexedNode) {
+                        // The template lowering doesn't really treat this as an array so you can't
+                        // store back into the varargs. Allocate your own array if you really need
+                        // this and EA should eliminate it.
+                        throw new GraalInternalError("Can't store into VarargsParameter array");
                     }
                 }
             } else {
--- a/src/share/vm/runtime/vmStructs.cpp	Tue Feb 11 22:41:50 2014 +0100
+++ b/src/share/vm/runtime/vmStructs.cpp	Tue Feb 11 15:07:50 2014 -0800
@@ -813,6 +813,34 @@
      static_field(StubRoutines,                _cipherBlockChaining_decryptAESCrypt,          address)                               \
      static_field(StubRoutines,                _updateBytesCRC32,                             address)                               \
      static_field(StubRoutines,                _crc_table_adr,                                address)                               \
+     static_field(StubRoutines,                _jbyte_arraycopy,                              address)                               \
+     static_field(StubRoutines,                _jshort_arraycopy,                             address)                               \
+     static_field(StubRoutines,                _jint_arraycopy,                               address)                               \
+     static_field(StubRoutines,                _jlong_arraycopy,                              address)                               \
+     static_field(StubRoutines,                _oop_arraycopy,                                address)                               \
+     static_field(StubRoutines,                _oop_arraycopy_uninit,                         address)                               \
+     static_field(StubRoutines,                _jbyte_disjoint_arraycopy,                     address)                               \
+     static_field(StubRoutines,                _jshort_disjoint_arraycopy,                    address)                               \
+     static_field(StubRoutines,                _jint_disjoint_arraycopy,                      address)                               \
+     static_field(StubRoutines,                _jlong_disjoint_arraycopy,                     address)                               \
+     static_field(StubRoutines,                _oop_disjoint_arraycopy,                       address)                               \
+     static_field(StubRoutines,                _oop_disjoint_arraycopy_uninit,                address)                               \
+     static_field(StubRoutines,                _arrayof_jbyte_arraycopy,                      address)                               \
+     static_field(StubRoutines,                _arrayof_jshort_arraycopy,                     address)                               \
+     static_field(StubRoutines,                _arrayof_jint_arraycopy,                       address)                               \
+     static_field(StubRoutines,                _arrayof_jlong_arraycopy,                      address)                               \
+     static_field(StubRoutines,                _arrayof_oop_arraycopy,                        address)                               \
+     static_field(StubRoutines,                _arrayof_oop_arraycopy_uninit,                 address)                               \
+     static_field(StubRoutines,                _arrayof_jbyte_disjoint_arraycopy,             address)                               \
+     static_field(StubRoutines,                _arrayof_jshort_disjoint_arraycopy,            address)                               \
+     static_field(StubRoutines,                _arrayof_jint_disjoint_arraycopy,              address)                               \
+     static_field(StubRoutines,                _arrayof_jlong_disjoint_arraycopy,             address)                               \
+     static_field(StubRoutines,                _arrayof_oop_disjoint_arraycopy,               address)                               \
+     static_field(StubRoutines,                _arrayof_oop_disjoint_arraycopy_uninit,        address)                               \
+     static_field(StubRoutines,                _checkcast_arraycopy,                          address)                               \
+     static_field(StubRoutines,                _checkcast_arraycopy_uninit,                   address)                               \
+     static_field(StubRoutines,                _unsafe_arraycopy,                             address)                               \
+     static_field(StubRoutines,                _generic_arraycopy,                            address)                               \
                                                                                                                                      \
   /*****************/                                                                                                                \
   /* SharedRuntime */                                                                                                                \