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 }