1 /* 2 * Copyright (c) 2013, 2018, 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 24 25 package org.graalvm.compiler.replacements.nodes; 26 27 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8; 28 29 import java.util.Collections; 30 31 import org.graalvm.compiler.core.common.type.ObjectStamp; 32 import org.graalvm.compiler.core.common.type.Stamp; 33 import org.graalvm.compiler.core.common.type.StampFactory; 34 import org.graalvm.compiler.core.common.type.StampPair; 35 import org.graalvm.compiler.graph.NodeClass; 36 import org.graalvm.compiler.nodeinfo.NodeCycles; 37 import org.graalvm.compiler.nodeinfo.NodeInfo; 38 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; 39 import org.graalvm.compiler.nodes.ConstantNode; 40 import org.graalvm.compiler.nodes.NodeView; 41 import org.graalvm.compiler.nodes.ValueNode; 42 import org.graalvm.compiler.nodes.java.LoadFieldNode; 43 import org.graalvm.compiler.nodes.java.LoadIndexedNode; 44 import org.graalvm.compiler.nodes.java.MonitorIdNode; 45 import org.graalvm.compiler.nodes.spi.ArrayLengthProvider; 46 import org.graalvm.compiler.nodes.spi.VirtualizableAllocation; 47 import org.graalvm.compiler.nodes.spi.VirtualizerTool; 48 import org.graalvm.compiler.nodes.util.GraphUtil; 49 import org.graalvm.compiler.nodes.virtual.VirtualArrayNode; 50 import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode; 51 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; 52 53 import jdk.vm.ci.meta.Assumptions; 54 import jdk.vm.ci.meta.ConstantReflectionProvider; 55 import jdk.vm.ci.meta.JavaKind; 56 import jdk.vm.ci.meta.ResolvedJavaField; 57 import jdk.vm.ci.meta.ResolvedJavaMethod; 58 import jdk.vm.ci.meta.ResolvedJavaType; 59 60 @NodeInfo(cycles = NodeCycles.CYCLES_UNKNOWN, size = SIZE_8) 61 public abstract class BasicObjectCloneNode extends MacroStateSplitNode implements VirtualizableAllocation, ArrayLengthProvider { 62 63 public static final NodeClass<BasicObjectCloneNode> TYPE = NodeClass.create(BasicObjectCloneNode.class); 64 65 public BasicObjectCloneNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode... arguments) { 66 super(c, invokeKind, targetMethod, bci, returnStamp, arguments); 67 updateStamp(computeStamp(getObject())); 68 } 69 70 @Override 71 public boolean inferStamp() { 72 return updateStamp(stamp.improveWith(computeStamp(getObject()))); 73 } 74 75 protected Stamp computeStamp(ValueNode object) { 76 Stamp objectStamp = object.stamp(NodeView.DEFAULT); 77 if (objectStamp instanceof ObjectStamp) { 78 objectStamp = objectStamp.join(StampFactory.objectNonNull()); 79 } 80 return objectStamp; 81 } 82 83 public ValueNode getObject() { 84 return arguments.get(0); 85 } 86 87 /* 88 * Looks at the given stamp and determines if it is an exact type (or can be assumed to be an 89 * exact type) and if it is a cloneable type. 90 * 91 * If yes, then the exact type is returned, otherwise it returns null. 92 */ 93 protected ResolvedJavaType getConcreteType(Stamp forStamp) { 94 if (!(forStamp instanceof ObjectStamp)) { 95 return null; 96 } 97 ObjectStamp objectStamp = (ObjectStamp) forStamp; 98 if (objectStamp.type() == null) { 99 return null; 100 } else if (objectStamp.isExactType()) { 101 return objectStamp.type().isCloneableWithAllocation() ? objectStamp.type() : null; 102 } else if (objectStamp.type().isArray()) { 103 return objectStamp.type(); 104 } 105 return null; 106 } 107 108 protected LoadFieldNode genLoadFieldNode(Assumptions assumptions, ValueNode originalAlias, ResolvedJavaField field) { 109 return LoadFieldNode.create(assumptions, originalAlias, field); 110 } 111 112 protected LoadIndexedNode genLoadIndexedNode(Assumptions assumptions, ValueNode originalAlias, ValueNode index, JavaKind elementKind) { 113 return new LoadIndexedNode(assumptions, originalAlias, index, null, elementKind); 114 } 115 116 @Override 117 public void virtualize(VirtualizerTool tool) { 118 ValueNode originalAlias = tool.getAlias(getObject()); 119 if (originalAlias instanceof VirtualObjectNode) { 120 VirtualObjectNode originalVirtual = (VirtualObjectNode) originalAlias; 121 if (originalVirtual.type().isCloneableWithAllocation()) { 122 ValueNode[] newEntryState = new ValueNode[originalVirtual.entryCount()]; 123 for (int i = 0; i < newEntryState.length; i++) { 124 newEntryState[i] = tool.getEntry(originalVirtual, i); 125 } 126 VirtualObjectNode newVirtual = originalVirtual.duplicate(); 127 tool.createVirtualObject(newVirtual, newEntryState, Collections.<MonitorIdNode> emptyList(), false); 128 tool.replaceWithVirtual(newVirtual); 129 } 130 } else { 131 ResolvedJavaType type = getConcreteType(originalAlias.stamp(NodeView.DEFAULT)); 132 if (type == null) { 133 return; 134 } 135 if (!type.isArray()) { 136 VirtualInstanceNode newVirtual = createVirtualInstanceNode(type, true); 137 ResolvedJavaField[] fields = newVirtual.getFields(); 138 139 ValueNode[] state = new ValueNode[fields.length]; 140 for (int i = 0; i < fields.length; i++) { 141 LoadFieldNode load = genLoadFieldNode(graph().getAssumptions(), originalAlias, fields[i]); 142 state[i] = load; 143 tool.addNode(load); 144 } 145 tool.createVirtualObject(newVirtual, state, Collections.<MonitorIdNode> emptyList(), false); 146 tool.replaceWithVirtual(newVirtual); 147 } else { 148 ValueNode length = findLength(FindLengthMode.SEARCH_ONLY, tool.getConstantReflection()); 149 if (length == null) { 150 return; 151 } 152 ValueNode lengthAlias = tool.getAlias(length); 153 if (!lengthAlias.isConstant()) { 154 return; 155 } 156 int constantLength = lengthAlias.asJavaConstant().asInt(); 157 if (constantLength >= 0 && constantLength <= tool.getMaximumEntryCount()) { 158 ValueNode[] state = new ValueNode[constantLength]; 159 ResolvedJavaType componentType = type.getComponentType(); 160 for (int i = 0; i < constantLength; i++) { 161 ConstantNode index = ConstantNode.forInt(i); 162 LoadIndexedNode load = genLoadIndexedNode(graph().getAssumptions(), originalAlias, index, componentType.getJavaKind()); 163 state[i] = load; 164 tool.addNode(index); 165 tool.addNode(load); 166 } 167 VirtualObjectNode virtualObject = new VirtualArrayNode(componentType, constantLength); 168 tool.createVirtualObject(virtualObject, state, Collections.<MonitorIdNode> emptyList(), false); 169 tool.replaceWithVirtual(virtualObject); 170 } 171 } 172 } 173 } 174 175 protected VirtualInstanceNode createVirtualInstanceNode(ResolvedJavaType type, boolean hasIdentity) { 176 return new VirtualInstanceNode(type, hasIdentity); 177 } 178 179 @Override 180 public ValueNode findLength(FindLengthMode mode, ConstantReflectionProvider constantReflection) { 181 return GraphUtil.arrayLength(getObject(), mode, constantReflection); 182 } 183 }