1 /*
   2  * Copyright (c) 2011, 2016, 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 package org.graalvm.compiler.nodes.memory;
  24 
  25 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
  26 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
  27 import static org.graalvm.compiler.nodes.NamedLocationIdentity.ARRAY_LENGTH_LOCATION;
  28 
  29 import org.graalvm.compiler.core.common.LIRKind;
  30 import org.graalvm.compiler.core.common.LocationIdentity;
  31 import org.graalvm.compiler.core.common.type.Stamp;
  32 import org.graalvm.compiler.core.common.type.StampFactory;
  33 import org.graalvm.compiler.debug.DebugCloseable;
  34 import org.graalvm.compiler.debug.GraalError;
  35 import org.graalvm.compiler.graph.Node;
  36 import org.graalvm.compiler.graph.NodeClass;
  37 import org.graalvm.compiler.graph.spi.Canonicalizable;
  38 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
  39 import org.graalvm.compiler.nodeinfo.InputType;
  40 import org.graalvm.compiler.nodeinfo.NodeInfo;
  41 import org.graalvm.compiler.nodes.CanonicalizableLocation;
  42 import org.graalvm.compiler.nodes.ConstantNode;
  43 import org.graalvm.compiler.nodes.FixedNode;
  44 import org.graalvm.compiler.nodes.FrameState;
  45 import org.graalvm.compiler.nodes.PiNode;
  46 import org.graalvm.compiler.nodes.ValueNode;
  47 import org.graalvm.compiler.nodes.extended.GuardingNode;
  48 import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
  49 import org.graalvm.compiler.nodes.memory.address.AddressNode;
  50 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
  51 import org.graalvm.compiler.nodes.spi.LIRLowerable;
  52 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  53 import org.graalvm.compiler.nodes.spi.Virtualizable;
  54 import org.graalvm.compiler.nodes.spi.VirtualizerTool;
  55 import org.graalvm.compiler.nodes.util.GraphUtil;
  56 
  57 import jdk.vm.ci.meta.Constant;
  58 import jdk.vm.ci.meta.MetaAccessProvider;
  59 
  60 /**
  61  * Reads an {@linkplain FixedAccessNode accessed} value.
  62  */
  63 @NodeInfo(nameTemplate = "Read#{p#location/s}", cycles = CYCLES_2, size = SIZE_1)
  64 public class ReadNode extends FloatableAccessNode implements LIRLowerable, Canonicalizable, Virtualizable, GuardingNode {
  65 
  66     public static final NodeClass<ReadNode> TYPE = NodeClass.create(ReadNode.class);
  67 
  68     public ReadNode(AddressNode address, LocationIdentity location, Stamp stamp, BarrierType barrierType) {
  69         super(TYPE, address, location, stamp, null, barrierType);
  70     }
  71 
  72     public ReadNode(AddressNode address, LocationIdentity location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
  73         super(TYPE, address, location, stamp, guard, barrierType);
  74     }
  75 
  76     public ReadNode(AddressNode address, LocationIdentity location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, FrameState stateBefore) {
  77         this(TYPE, address, location, stamp, guard, barrierType, nullCheck, stateBefore);
  78     }
  79 
  80     protected ReadNode(NodeClass<? extends ReadNode> c, AddressNode address, LocationIdentity location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck,
  81                     FrameState stateBefore) {
  82         super(c, address, location, stamp, guard, barrierType, nullCheck, stateBefore);
  83     }
  84 
  85     public ReadNode(AddressNode address, LocationIdentity location, ValueNode guard, BarrierType barrierType) {
  86         /*
  87          * Used by node intrinsics. Really, you can trust me on that! Since the initial value for
  88          * location is a parameter, i.e., a ParameterNode, the constructor cannot use the declared
  89          * type LocationNode.
  90          */
  91         super(TYPE, address, location, StampFactory.forNodeIntrinsic(), (GuardingNode) guard, barrierType);
  92     }
  93 
  94     @Override
  95     public void generate(NodeLIRBuilderTool gen) {
  96         LIRKind readKind = gen.getLIRGeneratorTool().getLIRKind(stamp());
  97         gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitLoad(readKind, gen.operand(address), gen.state(this)));
  98     }
  99 
 100     @Override
 101     public Node canonical(CanonicalizerTool tool) {
 102         if (tool.allUsagesAvailable() && hasNoUsages()) {
 103             if (getGuard() != null && !(getGuard() instanceof FixedNode)) {
 104                 // The guard is necessary even if the read goes away.
 105                 return new ValueAnchorNode((ValueNode) getGuard());
 106             } else {
 107                 // Read without usages or guard can be safely removed.
 108                 return null;
 109             }
 110         }
 111         if (getAddress() instanceof OffsetAddressNode) {
 112             OffsetAddressNode objAddress = (OffsetAddressNode) getAddress();
 113             if (objAddress.getBase() instanceof PiNode && ((PiNode) objAddress.getBase()).getGuard() == getGuard()) {
 114                 OffsetAddressNode newAddress = new OffsetAddressNode(((PiNode) objAddress.getBase()).getOriginalNode(), objAddress.getOffset());
 115                 return new ReadNode(newAddress, getLocationIdentity(), stamp(), getGuard(), getBarrierType(), getNullCheck(), stateBefore());
 116             }
 117         }
 118         if (!getNullCheck()) {
 119             return canonicalizeRead(this, getAddress(), getLocationIdentity(), tool);
 120         } else {
 121             // if this read is a null check, then replacing it with the value is incorrect for
 122             // guard-type usages
 123             return this;
 124         }
 125     }
 126 
 127     @SuppressWarnings("try")
 128     @Override
 129     public FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess) {
 130         try (DebugCloseable position = withNodeSourcePosition()) {
 131             return graph().unique(new FloatingReadNode(getAddress(), getLocationIdentity(), lastLocationAccess, stamp(), getGuard(), getBarrierType()));
 132         }
 133     }
 134 
 135     @Override
 136     public boolean isAllowedUsageType(InputType type) {
 137         return (getNullCheck() && type == InputType.Guard) ? true : super.isAllowedUsageType(type);
 138     }
 139 
 140     public static ValueNode canonicalizeRead(ValueNode read, AddressNode address, LocationIdentity locationIdentity, CanonicalizerTool tool) {
 141         MetaAccessProvider metaAccess = tool.getMetaAccess();
 142         if (tool.canonicalizeReads() && address instanceof OffsetAddressNode) {
 143             OffsetAddressNode objAddress = (OffsetAddressNode) address;
 144             ValueNode object = objAddress.getBase();
 145             if (metaAccess != null && object.isConstant() && !object.isNullConstant() && objAddress.getOffset().isConstant()) {
 146                 long displacement = objAddress.getOffset().asJavaConstant().asLong();
 147                 int stableDimension = ((ConstantNode) object).getStableDimension();
 148                 if (locationIdentity.isImmutable() || stableDimension > 0) {
 149                     Constant constant = read.stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), object.asConstant(), displacement);
 150                     boolean isDefaultStable = locationIdentity.isImmutable() || ((ConstantNode) object).isDefaultStable();
 151                     if (constant != null && (isDefaultStable || !constant.isDefaultForKind())) {
 152                         return ConstantNode.forConstant(read.stamp(), constant, Math.max(stableDimension - 1, 0), isDefaultStable, metaAccess);
 153                     }
 154                 }
 155             }
 156             if (locationIdentity.equals(ARRAY_LENGTH_LOCATION)) {
 157                 ValueNode length = GraphUtil.arrayLength(object);
 158                 if (length != null) {
 159                     // TODO Does this need a PiCastNode to the positive range?
 160                     return length;
 161                 }
 162             }
 163             if (locationIdentity instanceof CanonicalizableLocation) {
 164                 CanonicalizableLocation canonicalize = (CanonicalizableLocation) locationIdentity;
 165                 ValueNode result = canonicalize.canonicalizeRead(read, address, object, tool);
 166                 assert result != null && result.stamp().isCompatible(read.stamp());
 167                 return result;
 168             }
 169 
 170         }
 171         return read;
 172     }
 173 
 174     @Override
 175     public void virtualize(VirtualizerTool tool) {
 176         throw GraalError.shouldNotReachHere("unexpected ReadNode before PEA");
 177     }
 178 
 179     @Override
 180     public boolean canNullCheck() {
 181         return true;
 182     }
 183 }