001/*
002 * Copyright (c) 2011, 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.nodes.memory;
024
025import static com.oracle.graal.nodes.NamedLocationIdentity.*;
026import jdk.internal.jvmci.common.*;
027import jdk.internal.jvmci.meta.*;
028
029import com.oracle.graal.compiler.common.type.*;
030import com.oracle.graal.graph.*;
031import com.oracle.graal.graph.spi.*;
032import com.oracle.graal.nodeinfo.*;
033import com.oracle.graal.nodes.*;
034import com.oracle.graal.nodes.extended.*;
035import com.oracle.graal.nodes.memory.address.*;
036import com.oracle.graal.nodes.spi.*;
037import com.oracle.graal.nodes.util.*;
038
039/**
040 * Reads an {@linkplain FixedAccessNode accessed} value.
041 */
042@NodeInfo(nameTemplate = "Read#{p#location/s}")
043public final class ReadNode extends FloatableAccessNode implements LIRLowerable, Canonicalizable, Virtualizable, GuardingNode {
044
045    public static final NodeClass<ReadNode> TYPE = NodeClass.create(ReadNode.class);
046
047    public ReadNode(AddressNode address, LocationIdentity location, Stamp stamp, BarrierType barrierType) {
048        super(TYPE, address, location, stamp, null, barrierType);
049    }
050
051    public ReadNode(AddressNode address, LocationIdentity location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
052        super(TYPE, address, location, stamp, guard, barrierType);
053    }
054
055    public ReadNode(AddressNode address, LocationIdentity location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, FrameState stateBefore) {
056        super(TYPE, address, location, stamp, guard, barrierType, nullCheck, stateBefore);
057    }
058
059    public ReadNode(AddressNode address, LocationIdentity location, ValueNode guard, BarrierType barrierType) {
060        /*
061         * Used by node intrinsics. Really, you can trust me on that! Since the initial value for
062         * location is a parameter, i.e., a ParameterNode, the constructor cannot use the declared
063         * type LocationNode.
064         */
065        super(TYPE, address, location, StampFactory.forNodeIntrinsic(), (GuardingNode) guard, barrierType);
066    }
067
068    @Override
069    public void generate(NodeLIRBuilderTool gen) {
070        LIRKind readKind = gen.getLIRGeneratorTool().getLIRKind(stamp());
071        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, gen.operand(address), gen.state(this)));
072    }
073
074    @Override
075    public Node canonical(CanonicalizerTool tool) {
076        if (tool.allUsagesAvailable() && hasNoUsages()) {
077            if (getGuard() != null && !(getGuard() instanceof FixedNode)) {
078                // The guard is necessary even if the read goes away.
079                return new ValueAnchorNode((ValueNode) getGuard());
080            } else {
081                // Read without usages or guard can be safely removed.
082                return null;
083            }
084        }
085        if (getAddress() instanceof OffsetAddressNode) {
086            OffsetAddressNode objAddress = (OffsetAddressNode) getAddress();
087            if (objAddress.getBase() instanceof PiNode && ((PiNode) objAddress.getBase()).getGuard() == getGuard()) {
088                OffsetAddressNode newAddress = new OffsetAddressNode(((PiNode) objAddress.getBase()).getOriginalNode(), objAddress.getOffset());
089                return new ReadNode(newAddress, getLocationIdentity(), stamp(), getGuard(), getBarrierType(), getNullCheck(), stateBefore());
090            }
091        }
092        if (!getNullCheck()) {
093            return canonicalizeRead(this, getAddress(), getLocationIdentity(), tool);
094        } else {
095            // if this read is a null check, then replacing it with the value is incorrect for
096            // guard-type usages
097            return this;
098        }
099    }
100
101    @Override
102    public FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess) {
103        return graph().unique(new FloatingReadNode(getAddress(), getLocationIdentity(), lastLocationAccess, stamp(), getGuard(), getBarrierType()));
104    }
105
106    @Override
107    public boolean isAllowedUsageType(InputType type) {
108        return (getNullCheck() && type == InputType.Guard) ? true : super.isAllowedUsageType(type);
109    }
110
111    public static ValueNode canonicalizeRead(ValueNode read, AddressNode address, LocationIdentity locationIdentity, CanonicalizerTool tool) {
112        MetaAccessProvider metaAccess = tool.getMetaAccess();
113        if (tool.canonicalizeReads() && address instanceof OffsetAddressNode) {
114            OffsetAddressNode objAddress = (OffsetAddressNode) address;
115            ValueNode object = objAddress.getBase();
116            if (metaAccess != null && object.isConstant() && !object.isNullConstant() && objAddress.getOffset().isConstant()) {
117                long displacement = objAddress.getOffset().asJavaConstant().asLong();
118                if (locationIdentity.isImmutable()) {
119                    Constant constant = read.stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), object.asConstant(), displacement);
120                    if (constant != null) {
121                        return ConstantNode.forConstant(read.stamp(), constant, metaAccess);
122                    }
123                }
124
125                Constant constant = tool.getConstantReflection().readConstantArrayElementForOffset(object.asJavaConstant(), displacement);
126                if (constant != null) {
127                    return ConstantNode.forConstant(read.stamp(), constant, metaAccess);
128                }
129            }
130            if (locationIdentity.equals(ARRAY_LENGTH_LOCATION)) {
131                ValueNode length = GraphUtil.arrayLength(object);
132                if (length != null) {
133                    // TODO Does this need a PiCastNode to the positive range?
134                    return length;
135                }
136            }
137            if (locationIdentity instanceof CanonicalizableLocation) {
138                CanonicalizableLocation canonicalize = (CanonicalizableLocation) locationIdentity;
139                ValueNode result = canonicalize.canonicalizeRead(read, address, object, tool);
140                assert result != null && result.stamp().isCompatible(read.stamp());
141                return result;
142            }
143
144        }
145        return read;
146    }
147
148    @Override
149    public void virtualize(VirtualizerTool tool) {
150        throw JVMCIError.shouldNotReachHere("unexpected ReadNode before PEA");
151    }
152
153    public boolean canNullCheck() {
154        return true;
155    }
156}