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}