001/* 002 * Copyright (c) 2013, 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.replacements.nodes; 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.memory.*; 033import com.oracle.graal.nodes.spi.*; 034import com.oracle.graal.nodes.util.*; 035import com.oracle.graal.nodes.virtual.*; 036 037// JaCoCo Exclude 038 039/** 040 * Compares two arrays with the same length. 041 */ 042@NodeInfo 043public final class ArrayEqualsNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, Virtualizable, MemoryAccess { 044 045 public static final NodeClass<ArrayEqualsNode> TYPE = NodeClass.create(ArrayEqualsNode.class); 046 /** {@link Kind} of the arrays to compare. */ 047 protected final Kind kind; 048 049 /** One array to be tested for equality. */ 050 @Input ValueNode array1; 051 052 /** The other array to be tested for equality. */ 053 @Input ValueNode array2; 054 055 /** Length of both arrays. */ 056 @Input ValueNode length; 057 058 @OptionalInput(InputType.Memory) MemoryNode lastLocationAccess; 059 060 public ArrayEqualsNode(ValueNode array1, ValueNode array2, ValueNode length, @ConstantNodeParameter Kind kind) { 061 super(TYPE, StampFactory.forKind(Kind.Boolean)); 062 this.kind = kind; 063 this.array1 = array1; 064 this.array2 = array2; 065 this.length = length; 066 } 067 068 @Override 069 public Node canonical(CanonicalizerTool tool) { 070 if (tool.allUsagesAvailable() && hasNoUsages()) { 071 return null; 072 } 073 if (GraphUtil.unproxify(array1) == GraphUtil.unproxify(array2)) { 074 return ConstantNode.forBoolean(true); 075 } 076 return this; 077 } 078 079 public void virtualize(VirtualizerTool tool) { 080 ValueNode alias1 = tool.getAlias(array1); 081 ValueNode alias2 = tool.getAlias(array2); 082 if (alias1 == alias2) { 083 // the same virtual objects will always have the same contents 084 tool.replaceWithValue(ConstantNode.forBoolean(true, graph())); 085 } else if (alias1 instanceof VirtualObjectNode && alias2 instanceof VirtualObjectNode) { 086 VirtualObjectNode virtual1 = (VirtualObjectNode) alias1; 087 VirtualObjectNode virtual2 = (VirtualObjectNode) alias2; 088 089 if (virtual1.entryCount() == virtual2.entryCount()) { 090 int entryCount = virtual1.entryCount(); 091 boolean allEqual = true; 092 for (int i = 0; i < entryCount; i++) { 093 ValueNode entry1 = tool.getEntry(virtual1, i); 094 ValueNode entry2 = tool.getEntry(virtual2, i); 095 if (entry1 != entry2) { 096 // the contents might be different 097 allEqual = false; 098 } 099 if (entry1.stamp().alwaysDistinct(entry2.stamp())) { 100 // the contents are different 101 tool.replaceWithValue(ConstantNode.forBoolean(false, graph())); 102 return; 103 } 104 } 105 if (allEqual) { 106 tool.replaceWithValue(ConstantNode.forBoolean(true, graph())); 107 } 108 } 109 } 110 } 111 112 @NodeIntrinsic 113 public static native boolean equals(Object array1, Object array2, int length, @ConstantNodeParameter Kind kind); 114 115 public static boolean equals(boolean[] array1, boolean[] array2, int length) { 116 return equals(array1, array2, length, Kind.Boolean); 117 } 118 119 public static boolean equals(byte[] array1, byte[] array2, int length) { 120 return equals(array1, array2, length, Kind.Byte); 121 } 122 123 public static boolean equals(char[] array1, char[] array2, int length) { 124 return equals(array1, array2, length, Kind.Char); 125 } 126 127 public static boolean equals(short[] array1, short[] array2, int length) { 128 return equals(array1, array2, length, Kind.Short); 129 } 130 131 public static boolean equals(int[] array1, int[] array2, int length) { 132 return equals(array1, array2, length, Kind.Int); 133 } 134 135 public static boolean equals(long[] array1, long[] array2, int length) { 136 return equals(array1, array2, length, Kind.Long); 137 } 138 139 public static boolean equals(float[] array1, float[] array2, int length) { 140 return equals(array1, array2, length, Kind.Float); 141 } 142 143 public static boolean equals(double[] array1, double[] array2, int length) { 144 return equals(array1, array2, length, Kind.Double); 145 } 146 147 @Override 148 public void generate(NodeLIRBuilderTool gen) { 149 Value result = gen.getLIRGeneratorTool().emitArrayEquals(kind, gen.operand(array1), gen.operand(array2), gen.operand(length)); 150 gen.setResult(this, result); 151 } 152 153 public LocationIdentity getLocationIdentity() { 154 return NamedLocationIdentity.getArrayLocation(kind); 155 } 156 157 public MemoryNode getLastLocationAccess() { 158 return lastLocationAccess; 159 } 160 161 public void setLastLocationAccess(MemoryNode lla) { 162 updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(lla)); 163 lastLocationAccess = lla; 164 } 165}