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 25 26 package org.graalvm.compiler.hotspot.replacements.arraycopy; 27 28 import static org.graalvm.compiler.nodeinfo.InputType.Memory; 29 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; 30 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; 31 32 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; 33 import org.graalvm.compiler.core.common.type.Stamp; 34 import org.graalvm.compiler.core.common.type.StampFactory; 35 import org.graalvm.compiler.graph.Node; 36 import org.graalvm.compiler.graph.NodeClass; 37 import org.graalvm.compiler.graph.spi.Canonicalizable; 38 import org.graalvm.compiler.graph.spi.CanonicalizerTool; 39 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; 40 import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; 41 import org.graalvm.compiler.hotspot.nodes.GetObjectAddressNode; 42 import org.graalvm.compiler.nodeinfo.InputType; 43 import org.graalvm.compiler.nodeinfo.NodeInfo; 44 import org.graalvm.compiler.nodes.ConstantNode; 45 import org.graalvm.compiler.nodes.FixedWithNextNode; 46 import org.graalvm.compiler.nodes.NamedLocationIdentity; 47 import org.graalvm.compiler.nodes.NodeView; 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 import jdk.internal.vm.compiler.word.LocationIdentity; 62 63 import jdk.vm.ci.code.CodeUtil; 64 import jdk.vm.ci.meta.JavaConstant; 65 import jdk.vm.ci.meta.JavaKind; 66 import jdk.vm.ci.meta.MetaAccessProvider; 67 import jdk.vm.ci.meta.PrimitiveConstant; 68 69 @NodeInfo(allowedUsageTypes = {Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN) 70 public final class ArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single, MemoryAccess, Canonicalizable { 71 72 public static final NodeClass<ArrayCopyCallNode> TYPE = NodeClass.create(ArrayCopyCallNode.class); 73 @Input protected ValueNode src; 74 @Input protected ValueNode srcPos; 75 @Input protected ValueNode dest; 76 @Input protected ValueNode destPos; 77 @Input protected ValueNode length; 78 79 @OptionalInput(Memory) MemoryNode lastLocationAccess; 80 81 protected final JavaKind elementKind; 82 protected final LocationIdentity locationIdentity; 83 84 /** 85 * Aligned means that the offset of the copy is heap word aligned. 86 */ 87 protected boolean aligned; 88 protected boolean disjoint; 89 protected boolean uninitialized; 90 91 protected final HotSpotGraalRuntimeProvider runtime; 92 ArrayCopyCallNode(@njectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, boolean aligned, boolean disjoint, boolean uninitialized)93 public ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, 94 boolean aligned, boolean disjoint, boolean uninitialized) { 95 this(runtime, src, srcPos, dest, destPos, length, elementKind, null, aligned, disjoint, uninitialized); 96 } 97 ArrayCopyCallNode(@njectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, boolean disjoint)98 public ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, 99 boolean disjoint) { 100 this(runtime, src, srcPos, dest, destPos, length, elementKind, null, false, disjoint, false); 101 } 102 ArrayCopyCallNode(@njectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, LocationIdentity locationIdentity, boolean aligned, boolean disjoint, boolean uninitialized)103 protected ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, 104 LocationIdentity locationIdentity, boolean aligned, boolean disjoint, boolean uninitialized) { 105 super(TYPE, StampFactory.forVoid()); 106 assert elementKind != null; 107 this.src = src; 108 this.srcPos = srcPos; 109 this.dest = dest; 110 this.destPos = destPos; 111 this.length = length; 112 this.elementKind = elementKind; 113 this.locationIdentity = (locationIdentity != null ? locationIdentity : NamedLocationIdentity.getArrayLocation(elementKind)); 114 this.aligned = aligned; 115 this.disjoint = disjoint; 116 this.uninitialized = uninitialized; 117 this.runtime = runtime; 118 } 119 getSource()120 public ValueNode getSource() { 121 return src; 122 } 123 getSourcePosition()124 public ValueNode getSourcePosition() { 125 return srcPos; 126 } 127 getDestination()128 public ValueNode getDestination() { 129 return dest; 130 } 131 getDestinationPosition()132 public ValueNode getDestinationPosition() { 133 return destPos; 134 } 135 getLength()136 public ValueNode getLength() { 137 return length; 138 } 139 getElementKind()140 public JavaKind getElementKind() { 141 return elementKind; 142 } 143 computeBase(LoweringTool tool, ValueNode base, ValueNode pos)144 private ValueNode computeBase(LoweringTool tool, ValueNode base, ValueNode pos) { 145 FixedWithNextNode basePtr = graph().add(new GetObjectAddressNode(base)); 146 graph().addBeforeFixed(this, basePtr); 147 Stamp wordStamp = StampFactory.forKind(runtime.getTarget().wordJavaKind); 148 ValueNode wordPos = IntegerConvertNode.convert(pos, wordStamp, graph(), NodeView.DEFAULT); 149 int shift = CodeUtil.log2(tool.getMetaAccess().getArrayIndexScale(elementKind)); 150 ValueNode scaledIndex = graph().unique(new LeftShiftNode(wordPos, ConstantNode.forInt(shift, graph()))); 151 ValueNode offset = graph().unique(new AddNode(scaledIndex, ConstantNode.forIntegerStamp(wordStamp, tool.getMetaAccess().getArrayBaseOffset(elementKind), graph()))); 152 return graph().unique(new OffsetAddressNode(basePtr, offset)); 153 } 154 155 @Override lower(LoweringTool tool)156 public void lower(LoweringTool tool) { 157 if (graph().getGuardsStage().areFrameStatesAtDeopts()) { 158 updateAlignedDisjoint(tool.getMetaAccess()); 159 ForeignCallDescriptor desc = HotSpotHostForeignCallsProvider.lookupArraycopyDescriptor(elementKind, isAligned(), isDisjoint(), isUninitialized(), 160 locationIdentity.equals(LocationIdentity.any())); 161 StructuredGraph graph = graph(); 162 ValueNode srcAddr = computeBase(tool, getSource(), getSourcePosition()); 163 ValueNode destAddr = computeBase(tool, getDestination(), getDestinationPosition()); 164 ValueNode len = getLength(); 165 if (len.stamp(NodeView.DEFAULT).getStackKind() != JavaKind.Long) { 166 len = IntegerConvertNode.convert(len, StampFactory.forKind(JavaKind.Long), graph(), NodeView.DEFAULT); 167 } 168 ForeignCallNode call = graph.add(new ForeignCallNode(runtime.getHostBackend().getForeignCalls(), desc, srcAddr, destAddr, len)); 169 call.setStateAfter(stateAfter()); 170 graph.replaceFixedWithFixed(this, call); 171 } 172 } 173 174 @Override getLastLocationAccess()175 public MemoryNode getLastLocationAccess() { 176 return lastLocationAccess; 177 } 178 179 @Override setLastLocationAccess(MemoryNode lla)180 public void setLastLocationAccess(MemoryNode lla) { 181 updateUsagesInterface(lastLocationAccess, lla); 182 lastLocationAccess = lla; 183 } 184 185 @Override getLocationIdentity()186 public LocationIdentity getLocationIdentity() { 187 return locationIdentity; 188 } 189 190 @NodeIntrinsic arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind, @ConstantNodeParameter boolean aligned, @ConstantNodeParameter boolean disjoint, @ConstantNodeParameter boolean uninitialized)191 private static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind, @ConstantNodeParameter boolean aligned, 192 @ConstantNodeParameter boolean disjoint, @ConstantNodeParameter boolean uninitialized); 193 194 @NodeIntrinsic arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind, @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter boolean aligned, @ConstantNodeParameter boolean disjoint, @ConstantNodeParameter boolean uninitialized)195 private static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind, 196 @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter boolean aligned, @ConstantNodeParameter boolean disjoint, 197 @ConstantNodeParameter boolean uninitialized); 198 arraycopyObjectKillsAny(Object src, int srcPos, Object dest, int destPos, int length)199 public static void arraycopyObjectKillsAny(Object src, int srcPos, Object dest, int destPos, int length) { 200 arraycopy(src, srcPos, dest, destPos, length, JavaKind.Object, LocationIdentity.any(), false, false, false); 201 } 202 arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind)203 public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind) { 204 arraycopy(src, srcPos, dest, destPos, length, elementKind, false, false, false); 205 } 206 disjointArraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind)207 public static void disjointArraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind) { 208 arraycopy(src, srcPos, dest, destPos, length, elementKind, false, true, false); 209 } 210 disjointUninitializedArraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind)211 public static void disjointUninitializedArraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind) { 212 arraycopy(src, srcPos, dest, destPos, length, elementKind, false, true, true); 213 } 214 isAligned()215 public boolean isAligned() { 216 return aligned; 217 } 218 isDisjoint()219 public boolean isDisjoint() { 220 return disjoint; 221 } 222 isUninitialized()223 public boolean isUninitialized() { 224 return uninitialized; 225 } 226 isHeapWordAligned(MetaAccessProvider metaAccess, JavaConstant value, JavaKind kind)227 boolean isHeapWordAligned(MetaAccessProvider metaAccess, JavaConstant value, JavaKind kind) { 228 return (metaAccess.getArrayBaseOffset(kind) + (long) value.asInt() * metaAccess.getArrayIndexScale(kind)) % runtime.getVMConfig().heapWordSize == 0; 229 } 230 updateAlignedDisjoint(MetaAccessProvider metaAccess)231 public void updateAlignedDisjoint(MetaAccessProvider metaAccess) { 232 JavaKind componentKind = elementKind; 233 if (srcPos == destPos) { 234 // Can treat as disjoint 235 disjoint = true; 236 } 237 PrimitiveConstant constantSrc = (PrimitiveConstant) srcPos.stamp(NodeView.DEFAULT).asConstant(); 238 PrimitiveConstant constantDst = (PrimitiveConstant) destPos.stamp(NodeView.DEFAULT).asConstant(); 239 if (constantSrc != null && constantDst != null) { 240 if (!aligned) { 241 aligned = isHeapWordAligned(metaAccess, constantSrc, componentKind) && isHeapWordAligned(metaAccess, constantDst, componentKind); 242 } 243 if (constantSrc.asInt() >= constantDst.asInt()) { 244 // low to high copy so treat as disjoint 245 disjoint = true; 246 } 247 } 248 } 249 250 @Override canonical(CanonicalizerTool tool)251 public Node canonical(CanonicalizerTool tool) { 252 if (getLength().isConstant() && getLength().asConstant().isDefaultForKind()) { 253 if (lastLocationAccess != null) { 254 replaceAtUsages(InputType.Memory, lastLocationAccess.asNode()); 255 } 256 return null; 257 } 258 return this; 259 } 260 } 261