1/*
2 * Copyright (c) 2009, 2014, 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_2;
26import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
27
28import org.graalvm.compiler.core.common.type.StampFactory;
29import org.graalvm.compiler.graph.NodeClass;
30import org.graalvm.compiler.graph.spi.Canonicalizable;
31import org.graalvm.compiler.graph.spi.CanonicalizerTool;
32import org.graalvm.compiler.nodeinfo.NodeInfo;
33import org.graalvm.compiler.nodes.ConstantNode;
34import org.graalvm.compiler.nodes.FixedWithNextNode;
35import org.graalvm.compiler.nodes.ValueNode;
36import org.graalvm.compiler.nodes.ValueProxyNode;
37import org.graalvm.compiler.nodes.spi.Lowerable;
38import org.graalvm.compiler.nodes.spi.LoweringTool;
39import org.graalvm.compiler.nodes.spi.ValueProxy;
40import org.graalvm.compiler.nodes.spi.Virtualizable;
41import org.graalvm.compiler.nodes.spi.VirtualizerTool;
42import org.graalvm.compiler.nodes.util.GraphUtil;
43import org.graalvm.compiler.nodes.virtual.VirtualArrayNode;
44
45import jdk.vm.ci.meta.ConstantReflectionProvider;
46import jdk.vm.ci.meta.JavaConstant;
47
48/**
49 * The {@code ArrayLength} instruction gets the length of an array.
50 */
51@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
52public final class ArrayLengthNode extends FixedWithNextNode implements Canonicalizable.Unary<ValueNode>, Lowerable, Virtualizable {
53
54    public static final NodeClass<ArrayLengthNode> TYPE = NodeClass.create(ArrayLengthNode.class);
55    @Input ValueNode array;
56
57    public ValueNode array() {
58        return array;
59    }
60
61    @Override
62    public ValueNode getValue() {
63        return array;
64    }
65
66    public ArrayLengthNode(ValueNode array) {
67        super(TYPE, StampFactory.positiveInt());
68        this.array = array;
69    }
70
71    public static ValueNode create(ValueNode forValue, ConstantReflectionProvider constantReflection) {
72        if (forValue instanceof NewArrayNode) {
73            NewArrayNode newArray = (NewArrayNode) forValue;
74            return newArray.length();
75        }
76
77        ValueNode length = readArrayLengthConstant(forValue, constantReflection);
78        if (length != null) {
79            return length;
80        }
81        return new ArrayLengthNode(forValue);
82    }
83
84    @Override
85    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
86        ValueNode length = readArrayLength(forValue, tool.getConstantReflection());
87        if (length != null) {
88            return length;
89        }
90        return this;
91    }
92
93    /**
94     * Replicate the {@link ValueProxyNode}s from {@code originalValue} onto {@code value}.
95     *
96     * @param originalValue a possibly proxied value
97     * @param value a value needing proxies
98     * @return proxies wrapping {@code value}
99     */
100    private static ValueNode reproxyValue(ValueNode originalValue, ValueNode value) {
101        if (value.isConstant()) {
102            // No proxy needed
103            return value;
104        }
105        if (originalValue instanceof ValueProxyNode) {
106            ValueProxyNode proxy = (ValueProxyNode) originalValue;
107            return new ValueProxyNode(reproxyValue(proxy.getOriginalNode(), value), proxy.proxyPoint());
108        } else if (originalValue instanceof ValueProxy) {
109            ValueProxy proxy = (ValueProxy) originalValue;
110            return reproxyValue(proxy.getOriginalNode(), value);
111        } else {
112            return value;
113        }
114    }
115
116    /**
117     * Gets the length of an array if possible.
118     *
119     * @return a node representing the length of {@code array} or null if it is not available
120     */
121    public static ValueNode readArrayLength(ValueNode originalArray, ConstantReflectionProvider constantReflection) {
122        ValueNode length = GraphUtil.arrayLength(originalArray);
123        if (length != null) {
124            // Ensure that any proxies on the original value end up on the length value
125            return reproxyValue(originalArray, length);
126        }
127        return readArrayLengthConstant(originalArray, constantReflection);
128    }
129
130    private static ValueNode readArrayLengthConstant(ValueNode originalArray, ConstantReflectionProvider constantReflection) {
131        ValueNode array = GraphUtil.unproxify(originalArray);
132        if (constantReflection != null && array.isConstant() && !array.isNullConstant()) {
133            JavaConstant constantValue = array.asJavaConstant();
134            if (constantValue != null && constantValue.isNonNull()) {
135                Integer constantLength = constantReflection.readArrayLength(constantValue);
136                if (constantLength != null) {
137                    return ConstantNode.forInt(constantLength);
138                }
139            }
140        }
141        return null;
142    }
143
144    @Override
145    public void lower(LoweringTool tool) {
146        tool.getLowerer().lower(this, tool);
147    }
148
149    @NodeIntrinsic
150    public static native int arrayLength(Object array);
151
152    @Override
153    public void virtualize(VirtualizerTool tool) {
154        ValueNode alias = tool.getAlias(array());
155        if (alias instanceof VirtualArrayNode) {
156            VirtualArrayNode virtualArray = (VirtualArrayNode) alias;
157            tool.replaceWithValue(ConstantNode.forInt(virtualArray.entryCount(), graph()));
158        }
159    }
160}
161