Skip to content

Commit 6178bf1

Browse files
committed
[GR-34687] Canonicalize Class.isAssignableFrom(Object.getClass()) to Class.isInstanceOf(Object).
PullRequest: graal/10120
2 parents d0577b6 + 607676f commit 6178bf1

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ClassIsAssignableFromNode.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.graalvm.compiler.core.common.type.Stamp;
3131
import org.graalvm.compiler.graph.Node;
3232
import org.graalvm.compiler.graph.NodeClass;
33+
import org.graalvm.compiler.nodes.extended.GetClassNode;
3334
import org.graalvm.compiler.nodes.spi.Canonicalizable;
3435
import org.graalvm.compiler.nodes.spi.CanonicalizerTool;
3536
import org.graalvm.compiler.nodeinfo.NodeInfo;
@@ -74,6 +75,14 @@ public ValueNode getOtherClass() {
7475

7576
@Override
7677
public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
78+
if (forY instanceof GetClassNode) {
79+
// Canonicalize `Class.isAssignableFrom(Object.getClass())` to
80+
// `Class.isInstance(Object)`.
81+
// For non-leaf types, `Object.getClass()` cannot only return a ValueNode stamped
82+
// java.lang.Class, which prevents folding to a isNull check when the Object argument is
83+
// constant and complicates ClassIsAssignableFrom in the other cases.
84+
return InstanceOfDynamicNode.create(tool.getAssumptions(), tool.getConstantReflection(), forX, ((GetClassNode) forY).getObject(), false);
85+
}
7786
if (forX.isConstant() && forY.isConstant()) {
7887
ConstantReflectionProvider constantReflection = tool.getConstantReflection();
7988
ResolvedJavaType thisType = constantReflection.asJavaType(forX.asJavaConstant());

compiler/src/org.graalvm.micro.benchmarks/src/micro/benchmarks/TypecheckBenchmark.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,4 +306,66 @@ public int repetitiveInstanceOfDynamic(ThreadState state) {
306306
return res;
307307
}
308308

309+
@Benchmark
310+
public boolean classIsAssignableFromShouldFold(ThreadState state) {
311+
return AA.class.isAssignableFrom(state.aa1.getClass());
312+
}
313+
314+
@Benchmark
315+
public boolean classIsInstanceShouldFold(ThreadState state) {
316+
return AA.class.isInstance(state.aa1);
317+
}
318+
319+
@Benchmark
320+
public boolean instanceOfClassShouldFold(ThreadState state) {
321+
return state.aa1 instanceof AA;
322+
}
323+
324+
@Benchmark
325+
public int classIsAssignableFrom(ThreadState state) {
326+
int res = 0;
327+
Object[] objects = state.object;
328+
for (int i = 0; i < objects.length; i++) {
329+
if (classIsAssignableFrom(objects[i])) {
330+
res++;
331+
}
332+
}
333+
return res;
334+
}
335+
336+
boolean classIsAssignableFrom(Object obj) {
337+
return AA1.class.isAssignableFrom(obj.getClass());
338+
}
339+
340+
@Benchmark
341+
public int classIsInstance(ThreadState state) {
342+
int res = 0;
343+
Object[] objects = state.object;
344+
for (int i = 0; i < objects.length; i++) {
345+
if (classIsInstance(objects[i])) {
346+
res++;
347+
}
348+
}
349+
return res;
350+
}
351+
352+
boolean classIsInstance(Object obj) {
353+
return AA1.class.isInstance(obj);
354+
}
355+
356+
@Benchmark
357+
public int instanceOfClass(ThreadState state) {
358+
int res = 0;
359+
Object[] objects = state.object;
360+
for (int i = 0; i < objects.length; i++) {
361+
if (instanceOfClass(objects[i])) {
362+
res++;
363+
}
364+
}
365+
return res;
366+
}
367+
368+
boolean instanceOfClass(Object obj) {
369+
return obj instanceof AA1;
370+
}
309371
}

0 commit comments

Comments
 (0)