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}