1 /* 2 * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 //JaCoCo Exclude 24 package org.graalvm.compiler.hotspot.replacements.arraycopy; 25 26 import static org.graalvm.compiler.nodeinfo.InputType.Memory; 27 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; 28 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; 29 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; 30 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale; 31 32 import org.graalvm.compiler.core.common.LocationIdentity; 33 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; 34 import org.graalvm.compiler.core.common.type.Stamp; 35 import org.graalvm.compiler.core.common.type.StampFactory; 36 import org.graalvm.compiler.graph.Node; 37 import org.graalvm.compiler.graph.NodeClass; 38 import org.graalvm.compiler.graph.spi.Canonicalizable; 39 import org.graalvm.compiler.graph.spi.CanonicalizerTool; 40 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; 41 import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; 42 import org.graalvm.compiler.hotspot.nodes.GetObjectAddressNode; 43 import org.graalvm.compiler.nodeinfo.InputType; 44 import org.graalvm.compiler.nodeinfo.NodeInfo; 45 import org.graalvm.compiler.nodes.ConstantNode; 46 import org.graalvm.compiler.nodes.FixedWithNextNode; 47 import org.graalvm.compiler.nodes.NamedLocationIdentity; 48 import org.graalvm.compiler.nodes.StructuredGraph; 49 import org.graalvm.compiler.nodes.ValueNode; 50 import org.graalvm.compiler.nodes.calc.AddNode; 51 import org.graalvm.compiler.nodes.calc.IntegerConvertNode; 52 import org.graalvm.compiler.nodes.calc.LeftShiftNode; 53 import org.graalvm.compiler.nodes.extended.ForeignCallNode; 54 import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; 55 import org.graalvm.compiler.nodes.memory.MemoryAccess; 56 import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; 57 import org.graalvm.compiler.nodes.memory.MemoryNode; 58 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; 59 import org.graalvm.compiler.nodes.spi.Lowerable; 60 import org.graalvm.compiler.nodes.spi.LoweringTool; 61 62 import jdk.vm.ci.code.CodeUtil; 63 import jdk.vm.ci.meta.JavaConstant; 64 import jdk.vm.ci.meta.JavaKind; 65 import jdk.vm.ci.meta.PrimitiveConstant; 66 67 @NodeInfo(allowedUsageTypes = {Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN) 68 public final class ArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single, MemoryAccess, Canonicalizable { 69 70 public static final NodeClass<ArrayCopyCallNode> TYPE = NodeClass.create(ArrayCopyCallNode.class); 71 @Input protected ValueNode src; 72 @Input protected ValueNode srcPos; 73 @Input protected ValueNode dest; 74 @Input protected ValueNode destPos; 75 @Input protected ValueNode length; 76 77 @OptionalInput(Memory) MemoryNode lastLocationAccess; 78 79 protected final JavaKind elementKind; 80 protected final LocationIdentity locationIdentity; 81 82 /** 83 * Aligned means that the offset of the copy is heap word aligned. 84 */ 85 protected boolean aligned; 86 protected boolean disjoint; 87 protected boolean uninitialized; 88 89 protected final HotSpotGraalRuntimeProvider runtime; 90 91 public ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, 92 boolean aligned, boolean disjoint, boolean uninitialized) { 93 this(runtime, src, srcPos, dest, destPos, length, elementKind, null, aligned, disjoint, uninitialized); 94 } 95 96 public ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, 97 boolean disjoint) { 98 this(runtime, src, srcPos, dest, destPos, length, elementKind, null, false, disjoint, false); 99 } 100 101 protected ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, 102 LocationIdentity locationIdentity, boolean aligned, boolean disjoint, boolean uninitialized) { 103 super(TYPE, StampFactory.forVoid()); 104 assert elementKind != null; 105 this.src = src; 106 this.srcPos = srcPos; 107 this.dest = dest; 108 this.destPos = destPos; 109 this.length = length; 110 this.elementKind = elementKind; 111 this.locationIdentity = (locationIdentity != null ? locationIdentity : NamedLocationIdentity.getArrayLocation(elementKind)); 112 this.aligned = aligned; 113 this.disjoint = disjoint; 114 this.uninitialized = uninitialized; 115 this.runtime = runtime; 116 } 117 118 public ValueNode getSource() { 119 return src; 120 } 121 122 public ValueNode getSourcePosition() { 123 return srcPos; 124 } 125 126 public ValueNode getDestination() { 127 return dest; 128 } 129 130 public ValueNode getDestinationPosition() { 131 return destPos; 132 } 133 134 public ValueNode getLength() { 135 return length; 136 } 137 138 public JavaKind getElementKind() { 139 return elementKind; 140 } 141 142 private ValueNode computeBase(ValueNode base, ValueNode pos) { 143 FixedWithNextNode basePtr = graph().add(new GetObjectAddressNode(base)); 144 graph().addBeforeFixed(this, basePtr); 145 Stamp wordStamp = StampFactory.forKind(runtime.getTarget().wordJavaKind); 146 ValueNode wordPos = IntegerConvertNode.convert(pos, wordStamp, graph()); 147 int shift = CodeUtil.log2(getArrayIndexScale(elementKind)); 148 ValueNode scaledIndex = graph().unique(new LeftShiftNode(wordPos, ConstantNode.forInt(shift, graph()))); 149 ValueNode offset = graph().unique(new AddNode(scaledIndex, ConstantNode.forIntegerStamp(wordStamp, getArrayBaseOffset(elementKind), graph()))); 150 return graph().unique(new OffsetAddressNode(basePtr, offset)); 151 } 152 153 @Override 154 public void lower(LoweringTool tool) { 155 if (graph().getGuardsStage().areFrameStatesAtDeopts()) { 156 updateAlignedDisjoint(); 157 ForeignCallDescriptor desc = HotSpotHostForeignCallsProvider.lookupArraycopyDescriptor(elementKind, isAligned(), isDisjoint(), isUninitialized(), 158 locationIdentity.equals(LocationIdentity.any())); 159 StructuredGraph graph = graph(); 160 ValueNode srcAddr = computeBase(getSource(), getSourcePosition()); 161 ValueNode destAddr = computeBase(getDestination(), getDestinationPosition()); 162 ValueNode len = getLength(); 163 if (len.stamp().getStackKind() != JavaKind.Long) { 164 len = IntegerConvertNode.convert(len, StampFactory.forKind(JavaKind.Long), graph()); 165 } 166 ForeignCallNode call = graph.add(new ForeignCallNode(runtime.getHostBackend().getForeignCalls(), desc, srcAddr, destAddr, len)); 167 call.setStateAfter(stateAfter()); 168 graph.replaceFixedWithFixed(this, call); 169 } 170 } 171 172 @Override 173 public MemoryNode getLastLocationAccess() { 174 return lastLocationAccess; 175 } 176 177 @Override 178 public void setLastLocationAccess(MemoryNode lla) { 179 updateUsagesInterface(lastLocationAccess, lla); 180 lastLocationAccess = lla; 181 } 182 183 @Override 184 public LocationIdentity getLocationIdentity() { 185 return locationIdentity; 186 } 187 188 @NodeIntrinsic 189 private static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind, @ConstantNodeParameter boolean aligned, 190 @ConstantNodeParameter boolean disjoint, @ConstantNodeParameter boolean uninitialized); 191 192 @NodeIntrinsic 193 private static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind, 194 @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter boolean aligned, @ConstantNodeParameter boolean disjoint, 195 @ConstantNodeParameter boolean uninitialized); 196 197 public static void arraycopyObjectKillsAny(Object src, int srcPos, Object dest, int destPos, int length) { 198 arraycopy(src, srcPos, dest, destPos, length, JavaKind.Object, LocationIdentity.any(), false, false, false); 199 } 200 201 public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind) { 202 arraycopy(src, srcPos, dest, destPos, length, elementKind, false, false, false); 203 } 204 205 public static void disjointArraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind) { 206 arraycopy(src, srcPos, dest, destPos, length, elementKind, false, true, false); 207 } 208 209 public static void disjointUninitializedArraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind) { 210 arraycopy(src, srcPos, dest, destPos, length, elementKind, false, true, true); 211 } 212 213 public boolean isAligned() { 214 return aligned; 215 } 216 217 public boolean isDisjoint() { 218 return disjoint; 219 } 220 221 public boolean isUninitialized() { 222 return uninitialized; 223 } 224 225 boolean isHeapWordAligned(JavaConstant value, JavaKind kind) { 226 return (getArrayBaseOffset(kind) + (long) value.asInt() * getArrayIndexScale(kind)) % runtime.getVMConfig().heapWordSize == 0; 227 } 228 229 public void updateAlignedDisjoint() { 230 JavaKind componentKind = elementKind; 231 if (srcPos == destPos) { 232 // Can treat as disjoint 233 disjoint = true; 234 } 235 PrimitiveConstant constantSrc = (PrimitiveConstant) srcPos.stamp().asConstant(); 236 PrimitiveConstant constantDst = (PrimitiveConstant) destPos.stamp().asConstant(); 237 if (constantSrc != null && constantDst != null) { 238 if (!aligned) { 239 aligned = isHeapWordAligned(constantSrc, componentKind) && isHeapWordAligned(constantDst, componentKind); 240 } 241 if (constantSrc.asInt() >= constantDst.asInt()) { 242 // low to high copy so treat as disjoint 243 disjoint = true; 244 } 245 } 246 } 247 248 @Override 249 public Node canonical(CanonicalizerTool tool) { 250 if (getLength().isConstant() && getLength().asConstant().isDefaultForKind()) { 251 if (lastLocationAccess != null) { 252 replaceAtUsages(InputType.Memory, lastLocationAccess.asNode()); 253 } 254 return null; 255 } 256 return this; 257 } 258 }