001/* 002 * Copyright (c) 2013, 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 */ 023package com.oracle.graal.replacements.nodes; 024 025import static jdk.internal.jvmci.meta.LocationIdentity.*; 026import com.oracle.graal.debug.*; 027import jdk.internal.jvmci.meta.*; 028 029import com.oracle.graal.compiler.common.type.*; 030import com.oracle.graal.graph.*; 031import com.oracle.graal.nodeinfo.*; 032import com.oracle.graal.nodes.*; 033import com.oracle.graal.nodes.java.*; 034import com.oracle.graal.nodes.memory.*; 035import com.oracle.graal.nodes.spi.*; 036import com.oracle.graal.nodes.type.*; 037import com.oracle.graal.nodes.virtual.*; 038 039@NodeInfo 040public class BasicArrayCopyNode extends AbstractMemoryCheckpoint implements Virtualizable, MemoryCheckpoint.Single, MemoryAccess, Lowerable, DeoptimizingNode.DeoptDuring { 041 042 public static final NodeClass<BasicArrayCopyNode> TYPE = NodeClass.create(BasicArrayCopyNode.class); 043 044 @Input protected ValueNode src; 045 @Input protected ValueNode srcPos; 046 @Input protected ValueNode dest; 047 @Input protected ValueNode destPos; 048 @Input protected ValueNode length; 049 050 @OptionalInput(InputType.State) FrameState stateDuring; 051 052 @OptionalInput(InputType.Memory) protected MemoryNode lastLocationAccess; 053 054 protected Kind elementKind; 055 056 protected int bci; 057 058 public BasicArrayCopyNode(NodeClass<? extends AbstractMemoryCheckpoint> type, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, int bci) { 059 super(type, StampFactory.forKind(Kind.Void)); 060 this.bci = bci; 061 this.src = src; 062 this.srcPos = srcPos; 063 this.dest = dest; 064 this.destPos = destPos; 065 this.length = length; 066 this.elementKind = elementKind != Kind.Illegal ? elementKind : null; 067 } 068 069 public BasicArrayCopyNode(NodeClass<? extends AbstractMemoryCheckpoint> type, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind) { 070 super(type, StampFactory.forKind(Kind.Void)); 071 this.bci = -6; 072 this.src = src; 073 this.srcPos = srcPos; 074 this.dest = dest; 075 this.destPos = destPos; 076 this.length = length; 077 this.elementKind = elementKind != Kind.Illegal ? elementKind : null; 078 } 079 080 public ValueNode getSource() { 081 return src; 082 } 083 084 public ValueNode getSourcePosition() { 085 return srcPos; 086 } 087 088 public ValueNode getDestination() { 089 return dest; 090 } 091 092 public ValueNode getDestinationPosition() { 093 return destPos; 094 } 095 096 public ValueNode getLength() { 097 return length; 098 } 099 100 public int getBci() { 101 return bci; 102 } 103 104 public Kind getElementKind() { 105 return elementKind; 106 } 107 108 @Override 109 public LocationIdentity getLocationIdentity() { 110 if (elementKind != null) { 111 return NamedLocationIdentity.getArrayLocation(elementKind); 112 } 113 return any(); 114 } 115 116 public MemoryNode getLastLocationAccess() { 117 return lastLocationAccess; 118 } 119 120 public void setLastLocationAccess(MemoryNode lla) { 121 updateUsagesInterface(lastLocationAccess, lla); 122 lastLocationAccess = lla; 123 } 124 125 @Override 126 public void lower(LoweringTool tool) { 127 tool.getLowerer().lower(this, tool); 128 } 129 130 private static boolean checkBounds(int position, int length, VirtualObjectNode virtualObject) { 131 return position >= 0 && position + length <= virtualObject.entryCount(); 132 } 133 134 private static boolean checkEntryTypes(int srcPos, int length, VirtualObjectNode src, ResolvedJavaType destComponentType, VirtualizerTool tool) { 135 if (destComponentType.getKind() == Kind.Object) { 136 for (int i = 0; i < length; i++) { 137 ValueNode entry = tool.getEntry(src, srcPos + i); 138 ResolvedJavaType type = StampTool.typeOrNull(entry); 139 if (type == null || !destComponentType.isAssignableFrom(type)) { 140 return false; 141 } 142 } 143 } 144 return true; 145 } 146 147 /* 148 * Returns true if this copy doesn't require store checks. Trivially true for primitive arrays. 149 */ 150 public boolean isExact() { 151 ResolvedJavaType srcType = StampTool.typeOrNull(getSource().stamp()); 152 ResolvedJavaType destType = StampTool.typeOrNull(getDestination().stamp()); 153 if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) { 154 return false; 155 } 156 if ((srcType.getComponentType().getKind().isPrimitive() && destType.getComponentType().equals(srcType.getComponentType())) || getSource() == getDestination()) { 157 return true; 158 } 159 160 if (StampTool.isExactType(getDestination().stamp())) { 161 if (destType != null && destType.isAssignableFrom(srcType)) { 162 return true; 163 } 164 } 165 return false; 166 } 167 168 @Override 169 public void virtualize(VirtualizerTool tool) { 170 ValueNode sourcePosition = tool.getAlias(getSourcePosition()); 171 ValueNode destinationPosition = tool.getAlias(getDestinationPosition()); 172 ValueNode replacedLength = tool.getAlias(getLength()); 173 174 if (sourcePosition.isConstant() && destinationPosition.isConstant() && replacedLength.isConstant()) { 175 int srcPosInt = sourcePosition.asJavaConstant().asInt(); 176 int destPosInt = destinationPosition.asJavaConstant().asInt(); 177 int len = replacedLength.asJavaConstant().asInt(); 178 ValueNode destAlias = tool.getAlias(getDestination()); 179 180 if (destAlias instanceof VirtualArrayNode) { 181 VirtualArrayNode destVirtual = (VirtualArrayNode) destAlias; 182 if (len < 0 || !checkBounds(destPosInt, len, destVirtual)) { 183 return; 184 } 185 ValueNode srcAlias = tool.getAlias(getSource()); 186 187 if (srcAlias instanceof VirtualObjectNode) { 188 if (!(srcAlias instanceof VirtualArrayNode)) { 189 return; 190 } 191 VirtualArrayNode srcVirtual = (VirtualArrayNode) srcAlias; 192 if (destVirtual.componentType().getKind() != Kind.Object) { 193 return; 194 } 195 if (srcVirtual.componentType().getKind() != Kind.Object) { 196 return; 197 } 198 if (!checkBounds(srcPosInt, len, srcVirtual)) { 199 return; 200 } 201 if (!checkEntryTypes(srcPosInt, len, srcVirtual, destVirtual.type().getComponentType(), tool)) { 202 return; 203 } 204 for (int i = 0; i < len; i++) { 205 tool.setVirtualEntry(destVirtual, destPosInt + i, tool.getEntry(srcVirtual, srcPosInt + i), false); 206 } 207 tool.delete(); 208 if (Debug.isLogEnabled()) { 209 Debug.log("virtualized arraycopyf(%s, %d, %s, %d, %d)", getSource(), srcPosInt, getDestination(), destPosInt, len); 210 } 211 } else { 212 ResolvedJavaType sourceType = StampTool.typeOrNull(srcAlias); 213 if (sourceType == null || !sourceType.isArray()) { 214 return; 215 } 216 ResolvedJavaType sourceComponentType = sourceType.getComponentType(); 217 ResolvedJavaType destComponentType = destVirtual.type().getComponentType(); 218 if (!sourceComponentType.equals(destComponentType)) { 219 return; 220 } 221 for (int i = 0; i < len; i++) { 222 LoadIndexedNode load = new LoadIndexedNode(srcAlias, ConstantNode.forInt(i + srcPosInt, graph()), destComponentType.getKind()); 223 tool.addNode(load); 224 tool.setVirtualEntry(destVirtual, destPosInt + i, load, false); 225 } 226 tool.delete(); 227 } 228 } 229 } 230 } 231 232 public boolean canDeoptimize() { 233 return true; 234 } 235 236 public FrameState stateDuring() { 237 return stateDuring; 238 } 239 240 public void setStateDuring(FrameState stateDuring) { 241 updateUsages(this.stateDuring, stateDuring); 242 this.stateDuring = stateDuring; 243 } 244 245 public void computeStateDuring(FrameState currentStateAfter) { 246 FrameState newStateDuring = currentStateAfter.duplicateModifiedDuringCall(getBci(), asNode().getKind()); 247 setStateDuring(newStateDuring); 248 } 249}