001/*
002 * Copyright (c) 2009, 2014, 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.java;
024
025import jdk.internal.jvmci.meta.*;
026
027import com.oracle.graal.compiler.common.type.*;
028import com.oracle.graal.graph.*;
029import com.oracle.graal.graph.spi.*;
030import com.oracle.graal.nodeinfo.*;
031import com.oracle.graal.nodes.*;
032import com.oracle.graal.nodes.spi.*;
033import com.oracle.graal.nodes.util.*;
034
035/**
036 * The {@code ArrayLength} instruction gets the length of an array.
037 */
038@NodeInfo
039public final class ArrayLengthNode extends FixedWithNextNode implements Canonicalizable.Unary<ValueNode>, Lowerable, Virtualizable {
040
041    public static final NodeClass<ArrayLengthNode> TYPE = NodeClass.create(ArrayLengthNode.class);
042    @Input ValueNode array;
043
044    public ValueNode array() {
045        return array;
046    }
047
048    public ValueNode getValue() {
049        return array;
050    }
051
052    public ArrayLengthNode(ValueNode array) {
053        super(TYPE, StampFactory.positiveInt());
054        this.array = array;
055    }
056
057    public static ValueNode create(ValueNode forValue, ConstantReflectionProvider constantReflection) {
058        if (forValue instanceof NewArrayNode) {
059            NewArrayNode newArray = (NewArrayNode) forValue;
060            return newArray.length();
061        }
062
063        ValueNode length = readArrayLengthConstant(forValue, constantReflection);
064        if (length != null) {
065            return length;
066        }
067        return new ArrayLengthNode(forValue);
068    }
069
070    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
071        ValueNode length = readArrayLength(forValue, tool.getConstantReflection());
072        if (length != null) {
073            return length;
074        }
075        return this;
076    }
077
078    /**
079     * Replicate the {@link ValueProxyNode}s from {@code originalValue} onto {@code value}.
080     *
081     * @param originalValue a possibly proxied value
082     * @param value a value needing proxies
083     * @return proxies wrapping {@code value}
084     */
085    private static ValueNode reproxyValue(ValueNode originalValue, ValueNode value) {
086        if (value.isConstant()) {
087            // No proxy needed
088            return value;
089        }
090        if (originalValue instanceof ValueProxyNode) {
091            ValueProxyNode proxy = (ValueProxyNode) originalValue;
092            return new ValueProxyNode(reproxyValue(proxy.getOriginalNode(), value), proxy.proxyPoint());
093        } else if (originalValue instanceof ValueProxy) {
094            ValueProxy proxy = (ValueProxy) originalValue;
095            return reproxyValue(proxy.getOriginalNode(), value);
096        } else {
097            return value;
098        }
099    }
100
101    /**
102     * Gets the length of an array if possible.
103     *
104     * @return a node representing the length of {@code array} or null if it is not available
105     */
106    public static ValueNode readArrayLength(ValueNode originalArray, ConstantReflectionProvider constantReflection) {
107        ValueNode length = GraphUtil.arrayLength(originalArray);
108        if (length != null) {
109            // Ensure that any proxies on the original value end up on the length value
110            return reproxyValue(originalArray, length);
111        }
112        return readArrayLengthConstant(originalArray, constantReflection);
113    }
114
115    private static ValueNode readArrayLengthConstant(ValueNode originalArray, ConstantReflectionProvider constantReflection) {
116        ValueNode array = GraphUtil.unproxify(originalArray);
117        if (constantReflection != null && array.isConstant() && !array.isNullConstant()) {
118            JavaConstant constantValue = array.asJavaConstant();
119            if (constantValue != null && constantValue.isNonNull()) {
120                Integer constantLength = constantReflection.readArrayLength(constantValue);
121                if (constantLength != null) {
122                    return ConstantNode.forInt(constantLength);
123                }
124            }
125        }
126        return null;
127    }
128
129    @Override
130    public void lower(LoweringTool tool) {
131        tool.getLowerer().lower(this, tool);
132    }
133
134    @NodeIntrinsic
135    public static native int arrayLength(Object array);
136
137    @Override
138    public void virtualize(VirtualizerTool tool) {
139        ValueNode alias = tool.getAlias(array());
140        ValueNode length = GraphUtil.arrayLength(alias);
141        if (length != null) {
142            ValueNode lengthAlias = tool.getAlias(length);
143            if (!lengthAlias.isAlive()) {
144                lengthAlias = graph().addOrUnique(lengthAlias);
145            }
146            tool.replaceWithValue(lengthAlias);
147        }
148    }
149}