001/* 002 * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023//JaCoCo Exclude 024package com.oracle.graal.hotspot.replacements.arraycopy; 025 026import jdk.internal.jvmci.code.*; 027import jdk.internal.jvmci.hotspot.*; 028import jdk.internal.jvmci.meta.*; 029 030import com.oracle.graal.api.runtime.*; 031import com.oracle.graal.compiler.common.spi.*; 032import com.oracle.graal.compiler.common.type.*; 033import com.oracle.graal.graph.*; 034import com.oracle.graal.graph.spi.*; 035import com.oracle.graal.hotspot.*; 036import com.oracle.graal.hotspot.meta.*; 037import com.oracle.graal.hotspot.nodes.*; 038import com.oracle.graal.nodeinfo.*; 039import com.oracle.graal.nodes.*; 040import com.oracle.graal.nodes.calc.*; 041import com.oracle.graal.nodes.extended.*; 042import com.oracle.graal.nodes.memory.*; 043import com.oracle.graal.nodes.memory.address.*; 044import com.oracle.graal.nodes.spi.*; 045import com.oracle.graal.runtime.*; 046 047@NodeInfo(allowedUsageTypes = {InputType.Memory}) 048public final class ArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single, MemoryAccess, Canonicalizable { 049 050 public static final NodeClass<ArrayCopyCallNode> TYPE = NodeClass.create(ArrayCopyCallNode.class); 051 @Input protected ValueNode src; 052 @Input protected ValueNode srcPos; 053 @Input protected ValueNode dest; 054 @Input protected ValueNode destPos; 055 @Input protected ValueNode length; 056 057 @OptionalInput(InputType.Memory) MemoryNode lastLocationAccess; 058 059 protected final Kind elementKind; 060 protected final LocationIdentity locationIdentity; 061 062 /** 063 * Aligned means that the offset of the copy is heap word aligned. 064 */ 065 protected boolean aligned; 066 protected boolean disjoint; 067 protected boolean uninitialized; 068 069 protected final HotSpotGraalRuntimeProvider runtime; 070 071 public ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, 072 boolean aligned, boolean disjoint, boolean uninitialized) { 073 this(runtime, src, srcPos, dest, destPos, length, elementKind, null, aligned, disjoint, uninitialized); 074 } 075 076 public ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, 077 boolean disjoint) { 078 this(runtime, src, srcPos, dest, destPos, length, elementKind, null, false, disjoint, false); 079 } 080 081 protected ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, 082 LocationIdentity locationIdentity, boolean aligned, boolean disjoint, boolean uninitialized) { 083 super(TYPE, StampFactory.forVoid()); 084 assert elementKind != null; 085 this.src = src; 086 this.srcPos = srcPos; 087 this.dest = dest; 088 this.destPos = destPos; 089 this.length = length; 090 this.elementKind = elementKind; 091 this.locationIdentity = (locationIdentity != null ? locationIdentity : NamedLocationIdentity.getArrayLocation(elementKind)); 092 this.aligned = aligned; 093 this.disjoint = disjoint; 094 this.uninitialized = uninitialized; 095 this.runtime = runtime; 096 } 097 098 public ValueNode getSource() { 099 return src; 100 } 101 102 public ValueNode getSourcePosition() { 103 return srcPos; 104 } 105 106 public ValueNode getDestination() { 107 return dest; 108 } 109 110 public ValueNode getDestinationPosition() { 111 return destPos; 112 } 113 114 public ValueNode getLength() { 115 return length; 116 } 117 118 public Kind getElementKind() { 119 return elementKind; 120 } 121 122 private ValueNode computeBase(ValueNode base, ValueNode pos) { 123 FixedWithNextNode basePtr = graph().add(new GetObjectAddressNode(base)); 124 graph().addBeforeFixed(this, basePtr); 125 HotSpotJVMCIRuntimeProvider jvmciRuntime = runtime.getJVMCIRuntime(); 126 Stamp wordStamp = StampFactory.forKind(runtime.getTarget().wordKind); 127 ValueNode wordPos = IntegerConvertNode.convert(pos, wordStamp, graph()); 128 int shift = CodeUtil.log2(jvmciRuntime.getArrayIndexScale(elementKind)); 129 ValueNode scaledIndex = graph().unique(new LeftShiftNode(wordPos, ConstantNode.forInt(shift, graph()))); 130 ValueNode offset = graph().unique(new AddNode(scaledIndex, ConstantNode.forIntegerStamp(wordStamp, jvmciRuntime.getArrayBaseOffset(elementKind), graph()))); 131 return graph().unique(new OffsetAddressNode(basePtr, offset)); 132 } 133 134 @Override 135 public void lower(LoweringTool tool) { 136 if (graph().getGuardsStage().areFrameStatesAtDeopts()) { 137 updateAlignedDisjoint(); 138 ForeignCallDescriptor desc = HotSpotHostForeignCallsProvider.lookupArraycopyDescriptor(elementKind, isAligned(), isDisjoint(), isUninitialized(), 139 locationIdentity.equals(LocationIdentity.any())); 140 StructuredGraph graph = graph(); 141 ValueNode srcAddr = computeBase(getSource(), getSourcePosition()); 142 ValueNode destAddr = computeBase(getDestination(), getDestinationPosition()); 143 ValueNode len = getLength(); 144 if (len.stamp().getStackKind() != Kind.Long) { 145 len = IntegerConvertNode.convert(len, StampFactory.forKind(Kind.Long), graph()); 146 } 147 ForeignCallNode call = graph.add(new ForeignCallNode(Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getForeignCalls(), desc, srcAddr, destAddr, len)); 148 call.setStateAfter(stateAfter()); 149 graph.replaceFixedWithFixed(this, call); 150 } 151 } 152 153 public MemoryNode getLastLocationAccess() { 154 return lastLocationAccess; 155 } 156 157 public void setLastLocationAccess(MemoryNode lla) { 158 updateUsagesInterface(lastLocationAccess, lla); 159 lastLocationAccess = lla; 160 } 161 162 @Override 163 public LocationIdentity getLocationIdentity() { 164 return locationIdentity; 165 } 166 167 @NodeIntrinsic 168 private static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind, @ConstantNodeParameter boolean aligned, 169 @ConstantNodeParameter boolean disjoint, @ConstantNodeParameter boolean uninitialized); 170 171 @NodeIntrinsic 172 private static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind, 173 @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter boolean aligned, @ConstantNodeParameter boolean disjoint, 174 @ConstantNodeParameter boolean uninitialized); 175 176 public static void arraycopyObjectKillsAny(Object src, int srcPos, Object dest, int destPos, int length) { 177 arraycopy(src, srcPos, dest, destPos, length, Kind.Object, LocationIdentity.any(), false, false, false); 178 } 179 180 public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind) { 181 arraycopy(src, srcPos, dest, destPos, length, elementKind, false, false, false); 182 } 183 184 public static void disjointArraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind) { 185 arraycopy(src, srcPos, dest, destPos, length, elementKind, false, true, false); 186 } 187 188 public static void disjointUninitializedArraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind) { 189 arraycopy(src, srcPos, dest, destPos, length, elementKind, false, true, true); 190 } 191 192 public boolean isAligned() { 193 return aligned; 194 } 195 196 public boolean isDisjoint() { 197 return disjoint; 198 } 199 200 public boolean isUninitialized() { 201 return uninitialized; 202 } 203 204 boolean isHeapWordAligned(JavaConstant value, Kind kind) { 205 HotSpotJVMCIRuntimeProvider jvmciRuntime = runtime.getJVMCIRuntime(); 206 return (jvmciRuntime.getArrayBaseOffset(kind) + (long) value.asInt() * jvmciRuntime.getArrayIndexScale(kind)) % runtime.getConfig().heapWordSize == 0; 207 } 208 209 public void updateAlignedDisjoint() { 210 Kind componentKind = elementKind; 211 if (srcPos == destPos) { 212 // Can treat as disjoint 213 disjoint = true; 214 } 215 PrimitiveConstant constantSrc = (PrimitiveConstant) srcPos.stamp().asConstant(); 216 PrimitiveConstant constantDst = (PrimitiveConstant) destPos.stamp().asConstant(); 217 if (constantSrc != null && constantDst != null) { 218 if (!aligned) { 219 aligned = isHeapWordAligned(constantSrc, componentKind) && isHeapWordAligned(constantDst, componentKind); 220 } 221 if (constantSrc.asInt() >= constantDst.asInt()) { 222 // low to high copy so treat as disjoint 223 disjoint = true; 224 } 225 } 226 } 227 228 @Override 229 public Node canonical(CanonicalizerTool tool) { 230 if (getLength().isConstant() && getLength().asConstant().isDefaultForKind()) { 231 if (lastLocationAccess != null) { 232 replaceAtUsages(InputType.Memory, lastLocationAccess.asNode()); 233 } 234 return null; 235 } 236 return this; 237 } 238}