LoadIndexedNode.java revision 13431:fa2686ded3a7
1/*
2 * Copyright (c) 2009, 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 */
23package org.graalvm.compiler.nodes.java;
24
25import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
26import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
27
28import org.graalvm.compiler.core.common.type.ObjectStamp;
29import org.graalvm.compiler.core.common.type.Stamp;
30import org.graalvm.compiler.core.common.type.StampFactory;
31import org.graalvm.compiler.core.common.type.TypeReference;
32import org.graalvm.compiler.graph.Node;
33import org.graalvm.compiler.graph.NodeClass;
34import org.graalvm.compiler.graph.spi.Canonicalizable;
35import org.graalvm.compiler.graph.spi.CanonicalizerTool;
36import org.graalvm.compiler.nodeinfo.NodeInfo;
37import org.graalvm.compiler.nodes.ConstantNode;
38import org.graalvm.compiler.nodes.ValueNode;
39import org.graalvm.compiler.nodes.spi.Virtualizable;
40import org.graalvm.compiler.nodes.spi.VirtualizerTool;
41import org.graalvm.compiler.nodes.type.StampTool;
42import org.graalvm.compiler.nodes.virtual.VirtualArrayNode;
43import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
44
45import jdk.vm.ci.meta.Assumptions;
46import jdk.vm.ci.meta.ConstantReflectionProvider;
47import jdk.vm.ci.meta.JavaConstant;
48import jdk.vm.ci.meta.JavaKind;
49import jdk.vm.ci.meta.MetaAccessProvider;
50import jdk.vm.ci.meta.ResolvedJavaType;
51
52/**
53 * The {@code LoadIndexedNode} represents a read from an element of an array.
54 */
55@NodeInfo(cycles = CYCLES_8, size = SIZE_8)
56public class LoadIndexedNode extends AccessIndexedNode implements Virtualizable, Canonicalizable {
57
58    public static final NodeClass<LoadIndexedNode> TYPE = NodeClass.create(LoadIndexedNode.class);
59
60    /**
61     * Creates a new LoadIndexedNode.
62     *
63     * @param array the instruction producing the array
64     * @param index the instruction producing the index
65     * @param elementKind the element type
66     */
67    public LoadIndexedNode(Assumptions assumptions, ValueNode array, ValueNode index, JavaKind elementKind) {
68        this(TYPE, createStamp(assumptions, array, elementKind), array, index, elementKind);
69    }
70
71    public static ValueNode create(Assumptions assumptions, ValueNode array, ValueNode index, JavaKind elementKind, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
72        ValueNode constant = tryConstantFold(array, index, metaAccess, constantReflection);
73        if (constant != null) {
74            return constant;
75        }
76        return new LoadIndexedNode(assumptions, array, index, elementKind);
77    }
78
79    protected LoadIndexedNode(NodeClass<? extends LoadIndexedNode> c, Stamp stamp, ValueNode array, ValueNode index, JavaKind elementKind) {
80        super(c, stamp, array, index, elementKind);
81    }
82
83    private static Stamp createStamp(Assumptions assumptions, ValueNode array, JavaKind kind) {
84        ResolvedJavaType type = StampTool.typeOrNull(array);
85        if (kind == JavaKind.Object && type != null && type.isArray()) {
86            return StampFactory.object(TypeReference.createTrusted(assumptions, type.getComponentType()));
87        } else {
88            JavaKind preciseKind = determinePreciseArrayElementType(array, kind);
89            return StampFactory.forKind(preciseKind);
90        }
91    }
92
93    private static JavaKind determinePreciseArrayElementType(ValueNode array, JavaKind kind) {
94        if (kind == JavaKind.Byte) {
95            ResolvedJavaType javaType = ((ObjectStamp) array.stamp()).type();
96            if (javaType != null && javaType.isArray() && javaType.getComponentType() != null && javaType.getComponentType().getJavaKind() == JavaKind.Boolean) {
97                return JavaKind.Boolean;
98            }
99        }
100        return kind;
101    }
102
103    @Override
104    public boolean inferStamp() {
105        return updateStamp(stamp.improveWith(createStamp(graph().getAssumptions(), array(), elementKind())));
106    }
107
108    @Override
109    public void virtualize(VirtualizerTool tool) {
110        ValueNode alias = tool.getAlias(array());
111        if (alias instanceof VirtualObjectNode) {
112            VirtualArrayNode virtual = (VirtualArrayNode) alias;
113            ValueNode indexValue = tool.getAlias(index());
114            int idx = indexValue.isConstant() ? indexValue.asJavaConstant().asInt() : -1;
115            if (idx >= 0 && idx < virtual.entryCount()) {
116                ValueNode entry = tool.getEntry(virtual, idx);
117                if (stamp.isCompatible(entry.stamp())) {
118                    tool.replaceWith(entry);
119                } else {
120                    assert stamp().getStackKind() == JavaKind.Int && (entry.stamp().getStackKind() == JavaKind.Long || entry.getStackKind() == JavaKind.Double ||
121                                    entry.getStackKind() == JavaKind.Illegal) : "Can only allow different stack kind two slot marker writes on one stot fields.";
122                }
123            }
124        }
125    }
126
127    @Override
128    public Node canonical(CanonicalizerTool tool) {
129        ValueNode constant = tryConstantFold(array(), index(), tool.getMetaAccess(), tool.getConstantReflection());
130        if (constant != null) {
131            return constant;
132        }
133        return this;
134    }
135
136    private static ValueNode tryConstantFold(ValueNode array, ValueNode index, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
137        if (array.isConstant() && !array.isNullConstant() && index.isConstant()) {
138            JavaConstant arrayConstant = array.asJavaConstant();
139            if (arrayConstant != null) {
140                int stableDimension = ((ConstantNode) array).getStableDimension();
141                if (stableDimension > 0) {
142                    JavaConstant constant = constantReflection.readArrayElement(arrayConstant, index.asJavaConstant().asInt());
143                    boolean isDefaultStable = ((ConstantNode) array).isDefaultStable();
144                    if (constant != null && (isDefaultStable || !constant.isDefaultForKind())) {
145                        return ConstantNode.forConstant(constant, stableDimension - 1, isDefaultStable, metaAccess);
146                    }
147                }
148            }
149        }
150        return null;
151    }
152}
153