1 /* 2 * Copyright (c) 2018, 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.nodes.java; 26 27 import static org.graalvm.compiler.core.common.calc.CanonicalCondition.EQ; 28 import static org.graalvm.compiler.debug.DebugContext.DETAILED_LEVEL; 29 import static org.graalvm.compiler.nodeinfo.InputType.Memory; 30 import static org.graalvm.compiler.nodeinfo.InputType.Value; 31 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8; 32 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8; 33 34 import org.graalvm.compiler.core.common.type.Stamp; 35 import org.graalvm.compiler.graph.NodeClass; 36 import org.graalvm.compiler.nodeinfo.NodeInfo; 37 import org.graalvm.compiler.nodes.LogicConstantNode; 38 import org.graalvm.compiler.nodes.LogicNode; 39 import org.graalvm.compiler.nodes.NodeView; 40 import org.graalvm.compiler.nodes.ValueNode; 41 import org.graalvm.compiler.nodes.calc.CompareNode; 42 import org.graalvm.compiler.nodes.calc.ConditionalNode; 43 import org.graalvm.compiler.nodes.calc.ObjectEqualsNode; 44 import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; 45 import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; 46 import org.graalvm.compiler.nodes.spi.Lowerable; 47 import org.graalvm.compiler.nodes.spi.LoweringTool; 48 import org.graalvm.compiler.nodes.spi.Virtualizable; 49 import org.graalvm.compiler.nodes.spi.VirtualizerTool; 50 import org.graalvm.compiler.nodes.virtual.VirtualArrayNode; 51 import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode; 52 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; 53 import jdk.internal.vm.compiler.word.LocationIdentity; 54 55 import jdk.vm.ci.meta.JavaKind; 56 import jdk.vm.ci.meta.ResolvedJavaField; 57 58 @NodeInfo(allowedUsageTypes = {Value, Memory}, cycles = CYCLES_8, size = SIZE_8) 59 public abstract class AbstractUnsafeCompareAndSwapNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single, Virtualizable { 60 public static final NodeClass<AbstractUnsafeCompareAndSwapNode> TYPE = NodeClass.create(AbstractUnsafeCompareAndSwapNode.class); 61 @Input ValueNode object; 62 @Input ValueNode offset; 63 @Input ValueNode expected; 64 @Input ValueNode newValue; 65 protected final JavaKind valueKind; 66 protected final LocationIdentity locationIdentity; 67 68 public AbstractUnsafeCompareAndSwapNode(NodeClass<? extends AbstractMemoryCheckpoint> c, Stamp stamp, ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, 69 JavaKind valueKind, LocationIdentity locationIdentity) { 70 super(c, stamp); 71 this.object = object; 72 this.offset = offset; 73 this.expected = expected; 74 this.newValue = newValue; 75 this.valueKind = valueKind; 76 this.locationIdentity = locationIdentity; 77 } 78 79 public ValueNode object() { 80 return object; 81 } 82 83 public ValueNode offset() { 84 return offset; 85 } 86 87 public ValueNode expected() { 88 return expected; 89 } 90 91 public ValueNode newValue() { 92 return newValue; 93 } 94 95 public JavaKind getValueKind() { 96 return valueKind; 97 } 98 99 @Override 100 public LocationIdentity getLocationIdentity() { 101 return locationIdentity; 102 } 103 104 @Override 105 public void lower(LoweringTool tool) { 106 tool.getLowerer().lower(this, tool); 107 } 108 109 @Override 110 public void virtualize(VirtualizerTool tool) { 111 ValueNode offsetAlias = tool.getAlias(offset); 112 if (!offsetAlias.isJavaConstant()) { 113 return; 114 } 115 long constantOffset = offsetAlias.asJavaConstant().asLong(); 116 ValueNode objectAlias = tool.getAlias(object); 117 int index; 118 if (objectAlias instanceof VirtualInstanceNode) { 119 VirtualInstanceNode obj = (VirtualInstanceNode) objectAlias; 120 121 ResolvedJavaField field = obj.type().findInstanceFieldWithOffset(constantOffset, expected.getStackKind()); 122 if (field == null) { 123 tool.getDebug().log(DETAILED_LEVEL, "%s.virtualize() -> Unknown field", this); 124 return; 125 } 126 index = obj.fieldIndex(field); 127 } else if (objectAlias instanceof VirtualArrayNode) { 128 VirtualArrayNode array = (VirtualArrayNode) objectAlias; 129 index = array.entryIndexForOffset(tool.getMetaAccess(), constantOffset, valueKind); 130 } else { 131 return; 132 } 133 if (index < 0) { 134 tool.getDebug().log(DETAILED_LEVEL, "%s.virtualize() -> Unknown index", this); 135 return; 136 } 137 VirtualObjectNode obj = (VirtualObjectNode) objectAlias; 138 ValueNode currentValue = tool.getEntry(obj, index); 139 ValueNode expectedAlias = tool.getAlias(this.expected); 140 141 LogicNode equalsNode = null; 142 if (valueKind.isObject()) { 143 equalsNode = ObjectEqualsNode.virtualizeComparison(expectedAlias, currentValue, graph(), tool); 144 } 145 if (equalsNode == null && !(expectedAlias instanceof VirtualObjectNode) && !(currentValue instanceof VirtualObjectNode)) { 146 equalsNode = CompareNode.createCompareNode(EQ, expectedAlias, currentValue, tool.getConstantReflection(), NodeView.DEFAULT); 147 } 148 if (equalsNode == null) { 149 tool.getDebug().log(DETAILED_LEVEL, "%s.virtualize() -> Expected and/or current values are virtual and the comparison can not be folded", this); 150 return; 151 } 152 153 ValueNode newValueAlias = tool.getAlias(this.newValue); 154 ValueNode fieldValue; 155 if (equalsNode instanceof LogicConstantNode) { 156 fieldValue = ((LogicConstantNode) equalsNode).getValue() ? newValue : currentValue; 157 } else { 158 if (currentValue instanceof VirtualObjectNode || newValueAlias instanceof VirtualObjectNode) { 159 tool.getDebug().log(DETAILED_LEVEL, "%s.virtualize() -> Unknown outcome and current or new value is virtual", this); 160 return; 161 } 162 fieldValue = ConditionalNode.create(equalsNode, newValueAlias, currentValue, NodeView.DEFAULT); 163 } 164 if (!tool.setVirtualEntry(obj, index, fieldValue, valueKind, constantOffset)) { 165 tool.getDebug().log(DETAILED_LEVEL, "%s.virtualize() -> Could not set virtual entry", this); 166 return; 167 } 168 tool.getDebug().log(DETAILED_LEVEL, "%s.virtualize() -> Success: virtualizing", this); 169 if (!equalsNode.isAlive()) { 170 tool.addNode(equalsNode); 171 } 172 if (!fieldValue.isAlive() && !(fieldValue instanceof VirtualObjectNode)) { 173 tool.addNode(fieldValue); 174 } 175 finishVirtualize(tool, equalsNode, currentValue); 176 } 177 178 protected abstract void finishVirtualize(VirtualizerTool tool, LogicNode equalsNode, ValueNode currentValue); 179 }