69
70 /** One array to be tested for equality. */
71 @Input ValueNode array1;
72
73 /** The other array to be tested for equality. */
74 @Input ValueNode array2;
75
76 /** Length of both arrays. */
77 @Input ValueNode length;
78
79 @OptionalInput(Memory) MemoryNode lastLocationAccess;
80
81 public ArrayEqualsNode(ValueNode array1, ValueNode array2, ValueNode length, @ConstantNodeParameter JavaKind kind) {
82 super(TYPE, StampFactory.forKind(JavaKind.Boolean));
83 this.kind = kind;
84 this.array1 = array1;
85 this.array2 = array2;
86 this.length = length;
87 }
88
89 public ValueNode getArray1() {
90 return array1;
91 }
92
93 public ValueNode getArray2() {
94 return array2;
95 }
96
97 public ValueNode getLength() {
98 return length;
99 }
100
101 private static boolean isNaNFloat(JavaConstant constant) {
102 JavaKind kind = constant.getJavaKind();
103 return (kind == JavaKind.Float && Float.isNaN(constant.asFloat())) || (kind == JavaKind.Double && Double.isNaN(constant.asDouble()));
104 }
105
106 private static boolean arrayEquals(ConstantReflectionProvider constantReflection, JavaConstant a, JavaConstant b, int len) {
107 for (int i = 0; i < len; i++) {
108 JavaConstant aElem = constantReflection.readArrayElement(a, i);
109 JavaConstant bElem = constantReflection.readArrayElement(b, i);
110 if (!constantReflection.constantEquals(aElem, bElem) && !(isNaNFloat(aElem) && isNaNFloat(bElem))) {
111 return false;
112 }
113 }
114 return true;
115 }
116
117 @Override
118 public Node canonical(CanonicalizerTool tool) {
119 if (tool.allUsagesAvailable() && hasNoUsages()) {
120 return null;
140 ValueNode alias1 = tool.getAlias(array1);
141 ValueNode alias2 = tool.getAlias(array2);
142 if (alias1 == alias2) {
143 // the same virtual objects will always have the same contents
144 tool.replaceWithValue(ConstantNode.forBoolean(true, graph()));
145 } else if (alias1 instanceof VirtualObjectNode && alias2 instanceof VirtualObjectNode) {
146 VirtualObjectNode virtual1 = (VirtualObjectNode) alias1;
147 VirtualObjectNode virtual2 = (VirtualObjectNode) alias2;
148
149 if (virtual1.entryCount() == virtual2.entryCount()) {
150 int entryCount = virtual1.entryCount();
151 boolean allEqual = true;
152 for (int i = 0; i < entryCount; i++) {
153 ValueNode entry1 = tool.getEntry(virtual1, i);
154 ValueNode entry2 = tool.getEntry(virtual2, i);
155 if (entry1 != entry2) {
156 if (entry1 instanceof ConstantNode && entry2 instanceof ConstantNode) {
157 // Float NaN constants are different constant nodes but treated as
158 // equal in Arrays.equals([F[F) or Arrays.equals([D[D).
159 if (entry1.getStackKind() == JavaKind.Float && entry2.getStackKind() == JavaKind.Float) {
160 float value1 = ((JavaConstant) ((ConstantNode) entry1).asConstant()).asFloat();
161 float value2 = ((JavaConstant) ((ConstantNode) entry2).asConstant()).asFloat();
162 if (Float.floatToIntBits(value1) != Float.floatToIntBits(value2)) {
163 allEqual = false;
164 }
165 } else if (entry1.getStackKind() == JavaKind.Double && entry2.getStackKind() == JavaKind.Double) {
166 double value1 = ((JavaConstant) ((ConstantNode) entry1).asConstant()).asDouble();
167 double value2 = ((JavaConstant) ((ConstantNode) entry2).asConstant()).asDouble();
168 if (Double.doubleToLongBits(value1) != Double.doubleToLongBits(value2)) {
169 allEqual = false;
170 }
171 } else {
172 allEqual = false;
173 }
174 } else {
175 // the contents might be different
176 allEqual = false;
177 }
178 }
179 if (entry1.stamp(NodeView.DEFAULT).alwaysDistinct(entry2.stamp(NodeView.DEFAULT))) {
180 // the contents are different
181 tool.replaceWithValue(ConstantNode.forBoolean(false, graph()));
182 return;
183 }
184 }
185 if (allEqual) {
186 tool.replaceWithValue(ConstantNode.forBoolean(true, graph()));
187 }
209 }
210
211 public static boolean equals(int[] array1, int[] array2, int length) {
212 return equals(array1, array2, length, JavaKind.Int);
213 }
214
215 public static boolean equals(long[] array1, long[] array2, int length) {
216 return equals(array1, array2, length, JavaKind.Long);
217 }
218
219 public static boolean equals(float[] array1, float[] array2, int length) {
220 return equals(array1, array2, length, JavaKind.Float);
221 }
222
223 public static boolean equals(double[] array1, double[] array2, int length) {
224 return equals(array1, array2, length, JavaKind.Double);
225 }
226
227 @Override
228 public void generate(NodeLIRBuilderTool gen) {
229 Value result = gen.getLIRGeneratorTool().emitArrayEquals(kind, gen.operand(array1), gen.operand(array2), gen.operand(length));
230 gen.setResult(this, result);
231 }
232
233 @Override
234 public LocationIdentity getLocationIdentity() {
235 return NamedLocationIdentity.getArrayLocation(kind);
236 }
237
238 @Override
239 public MemoryNode getLastLocationAccess() {
240 return lastLocationAccess;
241 }
242
243 @Override
244 public void setLastLocationAccess(MemoryNode lla) {
245 updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(lla));
246 lastLocationAccess = lla;
247 }
248 }
|
69
70 /** One array to be tested for equality. */
71 @Input ValueNode array1;
72
73 /** The other array to be tested for equality. */
74 @Input ValueNode array2;
75
76 /** Length of both arrays. */
77 @Input ValueNode length;
78
79 @OptionalInput(Memory) MemoryNode lastLocationAccess;
80
81 public ArrayEqualsNode(ValueNode array1, ValueNode array2, ValueNode length, @ConstantNodeParameter JavaKind kind) {
82 super(TYPE, StampFactory.forKind(JavaKind.Boolean));
83 this.kind = kind;
84 this.array1 = array1;
85 this.array2 = array2;
86 this.length = length;
87 }
88
89 private static boolean isNaNFloat(JavaConstant constant) {
90 JavaKind kind = constant.getJavaKind();
91 return (kind == JavaKind.Float && Float.isNaN(constant.asFloat())) || (kind == JavaKind.Double && Double.isNaN(constant.asDouble()));
92 }
93
94 private static boolean arrayEquals(ConstantReflectionProvider constantReflection, JavaConstant a, JavaConstant b, int len) {
95 for (int i = 0; i < len; i++) {
96 JavaConstant aElem = constantReflection.readArrayElement(a, i);
97 JavaConstant bElem = constantReflection.readArrayElement(b, i);
98 if (!constantReflection.constantEquals(aElem, bElem) && !(isNaNFloat(aElem) && isNaNFloat(bElem))) {
99 return false;
100 }
101 }
102 return true;
103 }
104
105 @Override
106 public Node canonical(CanonicalizerTool tool) {
107 if (tool.allUsagesAvailable() && hasNoUsages()) {
108 return null;
128 ValueNode alias1 = tool.getAlias(array1);
129 ValueNode alias2 = tool.getAlias(array2);
130 if (alias1 == alias2) {
131 // the same virtual objects will always have the same contents
132 tool.replaceWithValue(ConstantNode.forBoolean(true, graph()));
133 } else if (alias1 instanceof VirtualObjectNode && alias2 instanceof VirtualObjectNode) {
134 VirtualObjectNode virtual1 = (VirtualObjectNode) alias1;
135 VirtualObjectNode virtual2 = (VirtualObjectNode) alias2;
136
137 if (virtual1.entryCount() == virtual2.entryCount()) {
138 int entryCount = virtual1.entryCount();
139 boolean allEqual = true;
140 for (int i = 0; i < entryCount; i++) {
141 ValueNode entry1 = tool.getEntry(virtual1, i);
142 ValueNode entry2 = tool.getEntry(virtual2, i);
143 if (entry1 != entry2) {
144 if (entry1 instanceof ConstantNode && entry2 instanceof ConstantNode) {
145 // Float NaN constants are different constant nodes but treated as
146 // equal in Arrays.equals([F[F) or Arrays.equals([D[D).
147 if (entry1.getStackKind() == JavaKind.Float && entry2.getStackKind() == JavaKind.Float) {
148 float value1 = ((JavaConstant) entry1.asConstant()).asFloat();
149 float value2 = ((JavaConstant) entry2.asConstant()).asFloat();
150 if (Float.floatToIntBits(value1) != Float.floatToIntBits(value2)) {
151 allEqual = false;
152 }
153 } else if (entry1.getStackKind() == JavaKind.Double && entry2.getStackKind() == JavaKind.Double) {
154 double value1 = ((JavaConstant) entry1.asConstant()).asDouble();
155 double value2 = ((JavaConstant) entry2.asConstant()).asDouble();
156 if (Double.doubleToLongBits(value1) != Double.doubleToLongBits(value2)) {
157 allEqual = false;
158 }
159 } else {
160 allEqual = false;
161 }
162 } else {
163 // the contents might be different
164 allEqual = false;
165 }
166 }
167 if (entry1.stamp(NodeView.DEFAULT).alwaysDistinct(entry2.stamp(NodeView.DEFAULT))) {
168 // the contents are different
169 tool.replaceWithValue(ConstantNode.forBoolean(false, graph()));
170 return;
171 }
172 }
173 if (allEqual) {
174 tool.replaceWithValue(ConstantNode.forBoolean(true, graph()));
175 }
197 }
198
199 public static boolean equals(int[] array1, int[] array2, int length) {
200 return equals(array1, array2, length, JavaKind.Int);
201 }
202
203 public static boolean equals(long[] array1, long[] array2, int length) {
204 return equals(array1, array2, length, JavaKind.Long);
205 }
206
207 public static boolean equals(float[] array1, float[] array2, int length) {
208 return equals(array1, array2, length, JavaKind.Float);
209 }
210
211 public static boolean equals(double[] array1, double[] array2, int length) {
212 return equals(array1, array2, length, JavaKind.Double);
213 }
214
215 @Override
216 public void generate(NodeLIRBuilderTool gen) {
217 int constantLength = -1;
218 if (length.isConstant()) {
219 constantLength = length.asJavaConstant().asInt();
220 }
221 Value result = gen.getLIRGeneratorTool().emitArrayEquals(kind, gen.operand(array1), gen.operand(array2), gen.operand(length), constantLength, false);
222 gen.setResult(this, result);
223 }
224
225 @Override
226 public LocationIdentity getLocationIdentity() {
227 return NamedLocationIdentity.getArrayLocation(kind);
228 }
229
230 @Override
231 public MemoryNode getLastLocationAccess() {
232 return lastLocationAccess;
233 }
234
235 @Override
236 public void setLastLocationAccess(MemoryNode lla) {
237 updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(lla));
238 lastLocationAccess = lla;
239 }
240 }
|