# HG changeset patch # User Tom Rodriguez # Date 1392160070 28800 # Node ID f4dedec9b2258a9494dc36abd06d09751bd3b23c # Parent ebd2dfc2b780b6acbb7f3b98d2fbd68630aa66a5# Parent c4e5a685c6a12111f34ac0be6e7e62b0c1823f79 Merge diff -r c4e5a685c6a1 -r f4dedec9b225 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java --- 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; } /** diff -r c4e5a685c6a1 -r f4dedec9b225 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- 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; diff -r c4e5a685c6a1 -r f4dedec9b225 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java --- 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); + } } diff -r c4e5a685c6a1 -r f4dedec9b225 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java --- 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 @@ } } } + } diff -r c4e5a685c6a1 -r f4dedec9b225 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java --- 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 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.class); + arraycopyDescriptors[i][j] = new EnumMap(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"); diff -r c4e5a685c6a1 -r f4dedec9b225 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java --- 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 diff -r c4e5a685c6a1 -r f4dedec9b225 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java --- 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"); } diff -r c4e5a685c6a1 -r f4dedec9b225 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java --- 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; diff -r c4e5a685c6a1 -r f4dedec9b225 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java --- 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()) { diff -r c4e5a685c6a1 -r f4dedec9b225 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java 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 ImmutableCode = new OptionValue<>(false); + @Option(help = "") + public static final OptionValue CallArrayCopy = new OptionValue<>(true); + // Runtime settings @Option(help = "") public static final OptionValue SupportJsrBytecodes = new OptionValue<>(true); diff -r c4e5a685c6a1 -r f4dedec9b225 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- 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 { diff -r c4e5a685c6a1 -r f4dedec9b225 src/share/vm/runtime/vmStructs.cpp --- 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 */ \