# HG changeset patch # User Roland Schatz # Date 1371740396 -7200 # Node ID 8c8285e345cc9e7dfeb1471ce304bda420f3c25a # Parent 89c15a40ef35f6c72b17ab7a76328e3e62866290 Later lowering of arraycopy. diff -r 89c15a40ef35 -r 8c8285e345cc graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java Thu Jun 20 17:30:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java Thu Jun 20 16:59:56 2013 +0200 @@ -37,5 +37,7 @@ appendPhase(new ExpandLogicPhase()); appendPhase(new DeadCodeEliminationPhase()); + + appendPhase(new RemoveValueProxyPhase()); } } diff -r 89c15a40ef35 -r 8c8285e345cc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Thu Jun 20 17:30:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Thu Jun 20 16:59:56 2013 +0200 @@ -328,6 +328,8 @@ writeBarrierSnippets = new WriteBarrierSnippets.Templates(this, r, graalRuntime.getTarget()); boxingSnippets = new BoxingSnippets.Templates(this, r, graalRuntime.getTarget()); exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(this, r, graalRuntime.getTarget()); + + r.registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(this, r, graalRuntime.getTarget())); } public HotSpotGraalRuntime getGraalRuntime() { diff -r 89c15a40ef35 -r 8c8285e345cc 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 Thu Jun 20 17:30:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java Thu Jun 20 16:59:56 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -76,35 +76,11 @@ private static final Kind VECTOR_KIND = Kind.Long; private static final long VECTOR_SIZE = arrayIndexScale(Kind.Long); - private static void vectorizedCopy(Object src, int srcPos, Object dest, int destPos, int length, Kind baseKind) { + private static void checkedCopy(Object src, int srcPos, Object dest, int destPos, int length, Kind baseKind) { checkNonNull(src); checkNonNull(dest); checkLimits(src, srcPos, dest, destPos, length); - int header = arrayBaseOffset(baseKind); - int elementSize = arrayIndexScale(baseKind); - long byteLength = (long) length * elementSize; - long nonVectorBytes = byteLength % VECTOR_SIZE; - long srcOffset = (long) srcPos * elementSize; - long destOffset = (long) destPos * elementSize; - 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); - } - long vectorLength = byteLength - nonVectorBytes; - for (long i = vectorLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } else { - for (long i = 0; i < nonVectorBytes; i += elementSize) { - UnsafeStoreNode.store(dest, header, i + destOffset, UnsafeLoadNode.load(src, header, i + srcOffset, baseKind), baseKind); - } - for (long i = nonVectorBytes; i < byteLength; i += VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } + UnsafeArrayCopyNode.arraycopy(src, srcPos, dest, destPos, length, baseKind); } public static void checkNonNull(Object obj) { @@ -149,85 +125,49 @@ @Snippet public static void arraycopy(byte[] src, int srcPos, byte[] dest, int destPos, int length) { byteCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Byte); + checkedCopy(src, srcPos, dest, destPos, length, Kind.Byte); } @Snippet public static void arraycopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) { booleanCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Byte); + checkedCopy(src, srcPos, dest, destPos, length, Kind.Boolean); } @Snippet public static void arraycopy(char[] src, int srcPos, char[] dest, int destPos, int length) { charCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Char); + checkedCopy(src, srcPos, dest, destPos, length, Kind.Char); } @Snippet public static void arraycopy(short[] src, int srcPos, short[] dest, int destPos, int length) { shortCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Short); + checkedCopy(src, srcPos, dest, destPos, length, Kind.Short); } @Snippet public static void arraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) { intCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Int); + checkedCopy(src, srcPos, dest, destPos, length, Kind.Int); } @Snippet public static void arraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) { floatCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Float); + checkedCopy(src, srcPos, dest, destPos, length, Kind.Float); } @Snippet public static void arraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) { longCounter.inc(); - checkNonNull(src); - checkNonNull(dest); - checkLimits(src, srcPos, dest, destPos, length); - Kind baseKind = Kind.Long; - int header = arrayBaseOffset(baseKind); - long byteLength = (long) length * arrayIndexScale(baseKind); - long srcOffset = (long) srcPos * arrayIndexScale(baseKind); - long destOffset = (long) destPos * arrayIndexScale(baseKind); - if (src == dest && srcPos < destPos) { // bad aliased case - for (long i = byteLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } else { - for (long i = 0; i < byteLength; i += VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } + checkedCopy(src, srcPos, dest, destPos, length, Kind.Long); } @Snippet public static void arraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) { doubleCounter.inc(); - checkNonNull(src); - checkNonNull(dest); - checkLimits(src, srcPos, dest, destPos, length); - Kind baseKind = Kind.Double; - int header = arrayBaseOffset(baseKind); - long byteLength = (long) length * arrayIndexScale(baseKind); - long srcOffset = (long) srcPos * arrayIndexScale(baseKind); - long destOffset = (long) destPos * arrayIndexScale(baseKind); - if (src == dest && srcPos < destPos) { // bad aliased case - for (long i = byteLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } else { - for (long i = 0; i < byteLength; i += VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } + checkedCopy(src, srcPos, dest, destPos, length, Kind.Double); } @Snippet @@ -239,25 +179,7 @@ @Snippet public static void arrayObjectCopy(Object src, int srcPos, Object dest, int destPos, int length) { objectCounter.inc(); - checkNonNull(src); - checkNonNull(dest); - checkLimits(src, srcPos, dest, destPos, length); - final int scale = arrayIndexScale(Kind.Object); - int header = arrayBaseOffset(Kind.Object); - if (src == dest && srcPos < destPos) { // bad aliased case - long start = (long) (length - 1) * scale; - for (long i = start; i >= 0; i -= scale) { - Object a = UnsafeLoadNode.load(src, header, i + (long) srcPos * scale, Kind.Object); - DirectObjectStoreNode.storeObject(dest, header, i + (long) destPos * scale, a); - } - } else { - long end = (long) length * scale; - for (long i = 0; i < end; i += scale) { - Object a = UnsafeLoadNode.load(src, header, i + (long) srcPos * scale, Kind.Object); - DirectObjectStoreNode.storeObject(dest, header, i + (long) destPos * scale, a); - - } - } + checkedCopy(src, srcPos, dest, destPos, length, Kind.Object); if (length > 0) { GenericArrayRangeWriteBarrier.insertWriteBarrier(dest, destPos, length); } @@ -265,22 +187,20 @@ @Snippet public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) { - // loading the hubs also checks for nullness Word srcHub = loadHub(src); Word destHub = loadHub(dest); - int layoutHelper = checkArrayType(srcHub); - int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); - final boolean isObjectArray = ((layoutHelper & layoutHelperElementTypePrimitiveInPlace()) == 0); + if (probability(FAST_PATH_PROBABILITY, srcHub.equal(destHub)) && probability(FAST_PATH_PROBABILITY, src != dest)) { + int layoutHelper = checkArrayType(srcHub); + final boolean isObjectArray = ((layoutHelper & layoutHelperElementTypePrimitiveInPlace()) == 0); - if (probability(FAST_PATH_PROBABILITY, srcHub.equal(destHub)) && probability(FAST_PATH_PROBABILITY, src != dest)) { checkLimits(src, srcPos, dest, destPos, length); if (probability(FAST_PATH_PROBABILITY, isObjectArray)) { genericObjectExactCallCounter.inc(); arrayObjectCopy(src, srcPos, dest, destPos, length); } else { genericPrimitiveCallCounter.inc(); - arraycopyInnerloop(src, srcPos, dest, destPos, length, layoutHelper); + UnsafeArrayCopyNode.arraycopyPrimitive(src, srcPos, dest, destPos, length, layoutHelper); } } else { genericObjectCallCounter.inc(); @@ -288,33 +208,6 @@ } } - public static void arraycopyInnerloop(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper) { - int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); - int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); - - Word memory = (Word) Word.fromObject(src); - - Word srcOffset = (Word) Word.fromObject(src).add(headerSize).add(srcPos << log2ElementSize); - Word destOffset = (Word) Word.fromObject(dest).add(headerSize).add(destPos << log2ElementSize); - Word destStart = destOffset; - long sizeInBytes = ((long) length) << log2ElementSize; - Word destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize)); - - int nonVectorBytes = (int) (sizeInBytes % VECTOR_SIZE); - Word destNonVectorEnd = destStart.add(nonVectorBytes); - - while (destOffset.belowThan(destNonVectorEnd)) { - destOffset.writeByte(0, srcOffset.readByte(0, ANY_LOCATION), ANY_LOCATION); - destOffset = destOffset.add(1); - srcOffset = srcOffset.add(1); - } - while (destOffset.belowThan(destEnd)) { - destOffset.writeWord(0, srcOffset.readWord(0, ANY_LOCATION), ANY_LOCATION); - destOffset = destOffset.add(wordSize()); - srcOffset = srcOffset.add(wordSize()); - } - } - 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"); diff -r 89c15a40ef35 -r 8c8285e345cc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopyNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopyNode.java Thu Jun 20 16:59:56 2013 +0200 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.replacements; + +import static com.oracle.graal.api.meta.LocationIdentity.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; + +public final class UnsafeArrayCopyNode extends AbstractStateSplit implements Lowerable, MemoryCheckpoint.Single { + + @Input private ValueNode src; + @Input private ValueNode srcPos; + @Input private ValueNode dest; + @Input private ValueNode destPos; + @Input private ValueNode length; + @Input private ValueNode layoutHelper; + + private Kind elementKind; + + private UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper, Kind elementKind) { + super(StampFactory.forVoid()); + assert layoutHelper == null || elementKind == null; + this.src = src; + this.srcPos = srcPos; + this.dest = dest; + this.destPos = destPos; + this.length = length; + this.layoutHelper = layoutHelper; + this.elementKind = elementKind; + } + + private UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind) { + this(src, srcPos, dest, destPos, length, null, elementKind); + } + + private UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper) { + this(src, srcPos, dest, destPos, length, layoutHelper, null); + } + + public Kind getElementKind() { + return elementKind; + } + + @Override + public void lower(LoweringTool tool, LoweringType loweringType) { + if (loweringType == LoweringType.AFTER_GUARDS) { + UnsafeArrayCopySnippets.Templates templates = tool.getReplacements().getSnippetTemplateCache(UnsafeArrayCopySnippets.Templates.class); + templates.lower(this); + } + } + + public void addSnippetArguments(Arguments args) { + args.add("src", src); + args.add("srcPos", srcPos); + args.add("dest", dest); + args.add("destPos", destPos); + args.add("length", length); + if (layoutHelper != null) { + args.add("layoutHelper", layoutHelper); + } + } + + @Override + public LocationIdentity getLocationIdentity() { + if (elementKind == null) { + return ANY_LOCATION; + } else { + return NamedLocationIdentity.getArrayLocation(elementKind); + } + } + + @NodeIntrinsic + public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind); + + @NodeIntrinsic + public static native void arraycopyPrimitive(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper); +} diff -r 89c15a40ef35 -r 8c8285e345cc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopySnippets.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopySnippets.java Thu Jun 20 16:59:56 2013 +0200 @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.replacements; + +import static com.oracle.graal.api.meta.LocationIdentity.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; +import static com.oracle.graal.replacements.SnippetTemplate.*; +import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; +import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.word.*; + +public class UnsafeArrayCopySnippets implements Snippets { + + private static final Kind VECTOR_KIND = Kind.Long; + private static final long VECTOR_SIZE = arrayIndexScale(Kind.Long); + + private static void vectorizedCopy(Object src, int srcPos, Object dest, int destPos, int length, Kind baseKind) { + int header = arrayBaseOffset(baseKind); + int elementSize = arrayIndexScale(baseKind); + long byteLength = (long) length * elementSize; + long nonVectorBytes = byteLength % VECTOR_SIZE; + long srcOffset = (long) srcPos * elementSize; + long destOffset = (long) destPos * elementSize; + 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); + } + long vectorLength = byteLength - nonVectorBytes; + for (long i = vectorLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } else { + for (long i = 0; i < nonVectorBytes; i += elementSize) { + UnsafeStoreNode.store(dest, header, i + destOffset, UnsafeLoadNode.load(src, header, i + srcOffset, baseKind), baseKind); + } + for (long i = nonVectorBytes; i < byteLength; i += VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } + } + + @Snippet + public static void arraycopyByte(byte[] src, int srcPos, byte[] dest, int destPos, int length) { + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Byte); + } + + @Snippet + public static void arraycopyBoolean(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) { + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Byte); + } + + @Snippet + public static void arraycopyChar(char[] src, int srcPos, char[] dest, int destPos, int length) { + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Char); + } + + @Snippet + public static void arraycopyShort(short[] src, int srcPos, short[] dest, int destPos, int length) { + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Short); + } + + @Snippet + public static void arraycopyInt(int[] src, int srcPos, int[] dest, int destPos, int length) { + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Int); + } + + @Snippet + public static void arraycopyFloat(float[] src, int srcPos, float[] dest, int destPos, int length) { + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Float); + } + + @Snippet + public static void arraycopyLong(long[] src, int srcPos, long[] dest, int destPos, int length) { + Kind baseKind = Kind.Long; + int header = arrayBaseOffset(baseKind); + long byteLength = (long) length * arrayIndexScale(baseKind); + long srcOffset = (long) srcPos * arrayIndexScale(baseKind); + long destOffset = (long) destPos * arrayIndexScale(baseKind); + if (src == dest && srcPos < destPos) { // bad aliased case + for (long i = byteLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } else { + for (long i = 0; i < byteLength; i += VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } + } + + @Snippet + public static void arraycopyDouble(double[] src, int srcPos, double[] dest, int destPos, int length) { + Kind baseKind = Kind.Double; + int header = arrayBaseOffset(baseKind); + long byteLength = (long) length * arrayIndexScale(baseKind); + long srcOffset = (long) srcPos * arrayIndexScale(baseKind); + long destOffset = (long) destPos * arrayIndexScale(baseKind); + if (src == dest && srcPos < destPos) { // bad aliased case + for (long i = byteLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } else { + for (long i = 0; i < byteLength; i += VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } + } + + /** + * Does NOT perform store checks. + */ + @Snippet + public static void arraycopyObject(Object[] src, int srcPos, Object[] dest, int destPos, int length) { + final int scale = arrayIndexScale(Kind.Object); + int header = arrayBaseOffset(Kind.Object); + if (src == dest && srcPos < destPos) { // bad aliased case + long start = (long) (length - 1) * scale; + for (long i = start; i >= 0; i -= scale) { + Object a = UnsafeLoadNode.load(src, header, i + (long) srcPos * scale, Kind.Object); + DirectObjectStoreNode.storeObject(dest, header, i + (long) destPos * scale, a); + } + } else { + long end = (long) length * scale; + for (long i = 0; i < end; i += scale) { + Object a = UnsafeLoadNode.load(src, header, i + (long) srcPos * scale, Kind.Object); + DirectObjectStoreNode.storeObject(dest, header, i + (long) destPos * scale, a); + } + } + } + + @Snippet + public static void arraycopyPrimitive(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper) { + int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); + int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); + + Word srcOffset = (Word) Word.fromObject(src).add(headerSize).add(srcPos << log2ElementSize); + Word destOffset = (Word) Word.fromObject(dest).add(headerSize).add(destPos << log2ElementSize); + Word destStart = destOffset; + long sizeInBytes = ((long) length) << log2ElementSize; + Word destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize)); + + int nonVectorBytes = (int) (sizeInBytes % VECTOR_SIZE); + Word destNonVectorEnd = destStart.add(nonVectorBytes); + + while (destOffset.belowThan(destNonVectorEnd)) { + destOffset.writeByte(0, srcOffset.readByte(0, ANY_LOCATION), ANY_LOCATION); + destOffset = destOffset.add(1); + srcOffset = srcOffset.add(1); + } + while (destOffset.belowThan(destEnd)) { + destOffset.writeWord(0, srcOffset.readWord(0, ANY_LOCATION), ANY_LOCATION); + destOffset = destOffset.add(wordSize()); + srcOffset = srcOffset.add(wordSize()); + } + } + + public static class Templates extends AbstractTemplates { + + private final SnippetInfo[] arraycopySnippets; + private final SnippetInfo genericPrimitiveSnippet; + + public Templates(MetaAccessProvider runtime, Replacements replacements, TargetDescription target) { + super(runtime, replacements, target); + + arraycopySnippets = new SnippetInfo[Kind.values().length]; + arraycopySnippets[Kind.Boolean.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyBoolean"); + arraycopySnippets[Kind.Byte.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyByte"); + arraycopySnippets[Kind.Short.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyShort"); + arraycopySnippets[Kind.Char.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyChar"); + arraycopySnippets[Kind.Int.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyInt"); + arraycopySnippets[Kind.Long.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyLong"); + arraycopySnippets[Kind.Float.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyFloat"); + arraycopySnippets[Kind.Double.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyDouble"); + arraycopySnippets[Kind.Object.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyObject"); + + genericPrimitiveSnippet = snippet(UnsafeArrayCopySnippets.class, "arraycopyPrimitive"); + } + + public void lower(UnsafeArrayCopyNode node) { + Kind elementKind = node.getElementKind(); + SnippetInfo snippet; + if (elementKind == null) { + // primitive array of unknown kind + snippet = genericPrimitiveSnippet; + } else { + snippet = arraycopySnippets[elementKind.ordinal()]; + assert snippet != null : "arraycopy snippet for " + elementKind.name() + " not found"; + } + + Arguments args = new Arguments(snippet); + node.addSnippetArguments(args); + + SnippetTemplate template = template(args); + template.instantiate(runtime, node, DEFAULT_REPLACER, args); + } + } +}