Skip to content

Generate inline superclass test for Class.isAssignableFrom on Z #20855

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

matthewhall2
Copy link
Contributor

@matthewhall2 matthewhall2 commented Dec 18, 2024

Before this change, only the class equality test was done inline for Class.isAssignableFrom, and other cases relied on a C Helper.

Now, the common case of the SuperClass test is done inline, along with a castclasscache check. This allows us to avoid calling the C Helper in the case of normal (non-interface) classes.

Additionally we now also check, when possible, the class depths at compile time so we can fast-fail when fromClassDepth <= toClassDepth

This PR does not enable the change. It will be enabled in #20860

@matthewhall2 matthewhall2 force-pushed the assignableFrom_genSuperclassTest branch 2 times, most recently from 093a9de to e0ce9ec Compare December 18, 2024 20:39
@matthewhall2 matthewhall2 marked this pull request as draft December 18, 2024 20:41
@matthewhall2 matthewhall2 force-pushed the assignableFrom_genSuperclassTest branch 8 times, most recently from 32f0761 to 4da8d70 Compare December 19, 2024 21:33
@matthewhall2 matthewhall2 marked this pull request as ready for review December 19, 2024 22:00
@matthewhall2 matthewhall2 force-pushed the assignableFrom_genSuperclassTest branch from 4da8d70 to 6d94a59 Compare December 19, 2024 22:13
@matthewhall2 matthewhall2 force-pushed the assignableFrom_genSuperclassTest branch 3 times, most recently from d4d8676 to ce999ca Compare January 3, 2025 16:48
@matthewhall2
Copy link
Contributor Author

@r30shah can you review please?

generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, failLabel);
}
}
genTestIsSuper(cg, node, fromClassReg, toClassReg, sr1, sr2, NULL, NULL, toClassDepth, failLabel, successLabel, helperCallLabel, deps, NULL, false, NULL, NULL);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getTestIsSuper is used by checkAssignableFrom old code and old instance of and checkcast code. We should make the changes is new isAssignableFrom with intention to clean-up old code in mind. I would take a look at genTestIsSuper and genInstanceOfOrCheckcastSuperClassTest and refactor common code to the single function. Currently the code in both is repeated twice with some subtle changes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactored in #20906

@matthewhall2 matthewhall2 force-pushed the assignableFrom_genSuperclassTest branch from e49baeb to 63470fb Compare January 29, 2025 19:48
@matthewhall2 matthewhall2 force-pushed the assignableFrom_genSuperclassTest branch from 63470fb to b5725a5 Compare February 26, 2025 14:59
@matthewhall2 matthewhall2 marked this pull request as draft February 26, 2025 15:05
@matthewhall2 matthewhall2 force-pushed the assignableFrom_genSuperclassTest branch 7 times, most recently from 7e72a6a to a883a0c Compare February 28, 2025 18:26
@matthewhall2 matthewhall2 requested a review from r30shah July 8, 2025 18:22
@matthewhall2 matthewhall2 force-pushed the assignableFrom_genSuperclassTest branch 2 times, most recently from adf87a1 to 1b98b52 Compare July 8, 2025 19:04
Copy link
Contributor

@r30shah r30shah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @matthewhall2 , Some minor nitpicks, but overall I feel changes are good. Once you address the comments, please launch internal build for Java 8 for both z/OS and Linux on Z with the changes enabled for sanity.

Comment on lines 11833 to 11839
} else {
classSymRef = classNode->getSymbolReference();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not match the compiler coding style.

}

// try to find class depth
if (!isClassNodeLoadAddr && ((classNode->getOpCodeValue() != TR::aloadi) || (classNode->getSymbolReference() != comp->getSymRefTab()->findJavaLangClassFromClassSymbolRef()) ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick and goes to the personal coding style so take it as suggestion,
In multiline if condition, I would add the body in curly braces, just for making it clear.

TR::SymbolReference *symRef = classRef->getOpCode().hasSymbolReference() ? classRef->getSymbolReference() : NULL;
TR::StaticSymbol *classSym = ((NULL != symRef) && !symRef->isUnresolved()) ? (symRef ? symRef->getSymbol()->getStaticSymbol() : NULL) : NULL;
TR_OpaqueClassBlock * clazz = (NULL != classSym) ? (TR_OpaqueClassBlock *) classSym->getStaticAddress() : NULL;
classDepth = (NULL != clazz) ? (int32_t)TR::Compiler->cls.classDepthOf(clazz) : -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
classDepth = (NULL != clazz) ? (int32_t)TR::Compiler->cls.classDepthOf(clazz) : -1;
classDepth = (NULL != clazz) ? static_cast<int32_t>(TR::Compiler->cls.classDepthOf(clazz)) : -1;

TR::Register *fromClassReg = cg->evaluate(node->getFirstChild());
TR::Register *toClassReg = cg->evaluate(node->getSecondChild());
TR::Compilation *comp = cg->comp();
if (comp->getOption(TR_TraceCG))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code will be executed in the instruction selection, does this traceMsg serve any purpose when looking into the logs?

TR::Instruction *cursor = NULL;

if (comp->getOption(TR_TraceCG))
traceMsg(comp,"%s: Emitting Class Equality Test\n",node->getOpCode().getName());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra indentation.

cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/ClassEqualityTest", comp->signature()),1,TR::DebugCounter::Undetermined);
cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, toClassReg, fromClassReg, TR::InstOpCode::COND_BE, successLabel, false, false);
if (debugObj)
debugObj->addInstructionComment(cursor, "class equality test");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra indentation

debugObj->addInstructionComment(cursor, "toclass depth > fromClass depth at compile time - fast fail");
}
srm->stopUsingRegisters();
goto fastFail;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although we have some places in VM and GC code where we have used goto statement, we certainly have not used it in the compiler code, given the poor readability and maintainability, Can we avoid using that?

@matthewhall2 matthewhall2 force-pushed the assignableFrom_genSuperclassTest branch 4 times, most recently from 1310ca9 to 940890b Compare July 11, 2025 20:37
@matthewhall2 matthewhall2 requested a review from r30shah July 11, 2025 20:43
@matthewhall2 matthewhall2 force-pushed the assignableFrom_genSuperclassTest branch 2 times, most recently from 2dc9282 to 6491f80 Compare July 11, 2025 20:46
@matthewhall2
Copy link
Contributor Author

thanks @r30shah , I've addressed the comments
java 8 tests

Copy link
Contributor

@r30shah r30shah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@matthewhall2 - Can you share the instruction selection log with the recent changes ? Also some nitpicks.

* if equal, we are done. If not, fall through to helper call
*/
generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, toClassReg, fromClassReg, TR::InstOpCode::COND_BE, successLabel, false, false);
TR_S390ScratchRegisterManager *srm = cg->generateScratchRegisterManager(2);;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double semicolon at the end.

@matthewhall2 matthewhall2 force-pushed the assignableFrom_genSuperclassTest branch 6 times, most recently from d8813a9 to f0b0ca1 Compare July 14, 2025 19:25
@matthewhall2
Copy link
Contributor Author

matthewhall2 commented Jul 14, 2025

Here's the selection log

5541 ------------------------------
5542  n22n     (  0)  treetop                                                                              [     0x3ff5ae02ec0] bci=[-1,19,8] rc=0 vc=130 vn=- li=8 udi=- n
5543  n21n     (  0)    icall  jitCheckAssignable[#89  helper Method] [flags 0x400 0x0 ] (in GPR_0225) ()  [     0x3ff5ae02e70] bci=[-1,19,8] rc=0 vc=130 vn=- li=8 udi=- n
5544  n57n     (  1)      aloadi  <classFromJavaLangClass>[#315  Shadow +8] [flags 0x10607 0x0 ] (in GPR_0182) (X!=0 )  [     0x3ff5ae9e190] bci=[-1,17,8] rc=1 vc=130 vn=-
5545  n20n     (  0)        aloadi  <javaLangClassFromClass>[#314  Shadow +48] [flags 0x607 0x0 ] (in &GPR_0184) (X!=0 X>=0 )  [     0x3ff5ae02e20] bci=[-1,17,8] rc=0 vc=1
5546  n18n     (  0)          ==>loadaddr (in GPR_0176) (X>=0 )
5547  n56n     (  1)      ==>aloadi (in GPR_0178) (X!=0 )
5548 ------------------------------
5549
5550  [     0x3ff5af79b60]                          LG      &GPR_0184, Shadow[<javaLangClassFromClass>] 48(GPR_0176)
5551  [     0x3ff5af79c30]                          LG      GPR_0182, Shadow[<classFromJavaLangClass>] 8(&GPR_0184)
5552  [     0x3ff5af7c8d0]                          LHI     GPR_0225,0x1
5553  [     0x3ff5af7c9b0]                          Label L0069:     # (Start of internal control flow)
5554  [     0x3ff5af7cbe0]                          DCB     Spill Reg, Debug Counter Bump
5555  [     0x3ff5af7ccf0]                          CGRJ    GPR_0178,GPR_0182,Label L0067,BH(mask=0x8),       ; class equality test
5556  [     0x3ff5af7cf50]                          DCB     Spill Reg, Debug Counter Bump
5557  [     0x3ff5af7d240]                          DCB     Spill Reg, Debug Counter Bump
5558  [     0x3ff5af7d410]                          LG      GPR_0240,#428 200(GPR_0182)
5559  [     0x3ff5af7d4e0]                          CGRJ    GPR_0240,GPR_0178,Label L0067,BH(mask=0x8),       ; castclass cache test
5560  [     0x3ff5af7d740]                          DCB     Spill Reg, Debug Counter Bump
5561  [     0x3ff5af7d9a0]                          DCB     Spill Reg, Debug Counter Bump
5562  [     0x3ff5af7db70]                          LG      GPR_0240,#431 8(GPR_0178)
5563  [     0x3ff5af7dd00]                          L       GPR_0240,#432 16(GPR_0240) ; Load castClass modifiers
5564  [     0x3ff5af7ddf0]                          NILF    GPR_0240,66048
5565  [     0x3ff5af7df00]                          BRC     BNH(0x6), Outlined Label L0066
5566  [     0x3ff5af7e0c0]                          LLGH    GPR_0240,#433 30(GPR_0178) ; Load toClass depth
5567  [     0x3ff5af7e300]                          LLGH    GPR_0256,#434 30(GPR_0182) ; Load fromClass depth
5568  [     0x3ff5af7e3f0]                          CGRJ    GPR_0256,GPR_0240,Label L0068,BNL(mask=0xc),      ; Check if fromClassDepth <= toClassDepth and jump to fail
5569  [     0x3ff5af7e5c0]                          LG      GPR_0256,#435 16(GPR_0182) ; Load superclass array
5570  [     0x3ff5af7e6b0]                          SLLG    GPR_0240,GPR_0240,3
5571  [     0x3ff5af7e870]                          CG      GPR_0178,#436 0(GPR_0240,GPR_0256) ; check superclass array
5572  [     0x3ff5af7e960]                          BRC     BH(0x8), Label L0067
5573  [     0x3ff5af7eb90]                          DCB     Spill Reg, Debug Counter Bump
5574  [     0x3ff5af7eca0]                          BRC     NOP(0xf), Outlined Label L0066
5575  [     0x3ff5af7ed80]                          Label L0068:
5576  [     0x3ff5af7ee60]                          LHI     GPR_0225,0x0
5577  [     0x3ff5af7f5e0]                          assocreg
5578  [     0x3ff5af7f020]                          Label L0067:     # (End of internal control flow)
5579  POST:
5580  {AssignAny:GPR_0256:R} {AssignAny:GPR_0240:R} {AssignAny:GPR_0225:R} {AssignAny:GPR_0182:R} {AssignAny:GPR_0178:R}
5581
5582 ------------------------------
5583
5584  [     0x3ff5af79ef0]                          Outlined Label L0066:
5585  [     0x3ff5af7b250]                          LGR     GPR_0224,GPR13
5586  [     0x3ff5af7b7d0]                          STG     GPR5,#423 32(GPR13)
5587  [     0x3ff5af7be90]                          assocreg
5588   PRE:
5589  {GPR2:GPR_0224:R} {GPR3:GPR_0182:R} {GPR4:GPR_0178:R}
5590  [     0x3ff5af7b8a0]                          BRASL   GPR_0191,0x0000000000000000
5591  POST:
5592  [     0x3ff5af7c5d0]                          assocreg
5593  [     0x3ff5af7c020]                          LG      GPR5,#424 32(GPR13)
5594  POST:
5595  {GPR0:D_GPR_0186:D}* {GPR1:D_GPR_0187:D}* {GPR2:GPR_0188:D} {GPR3:D_GPR_0189:D}* {GPR4:D_GPR_0190:D}* {GPR14:GPR_0191:D} {FPR0:D_FPR_0192:D}* {FPR1:D_FPR_0193:D}*
5596  {FPR2:D_FPR_0194:D}* {FPR3:D_FPR_0195:D}* {FPR4:D_FPR_0196:D}* {FPR5:D_FPR_0197:D}* {FPR6:D_FPR_0198:D}* {FPR7:D_FPR_0199:D}* {FPR8:D_FPR_0200:D}* {FPR9:D_FPR_0201:D
5597  {FPR10:D_FPR_0202:D}* {FPR11:D_FPR_0203:D}* {FPR12:D_FPR_0204:D}* {FPR13:D_FPR_0205:D}* {FPR14:D_FPR_0206:D}* {FPR15:D_FPR_0207:D}* {VRF16:D_VRF_0208:D}* {VRF17:D_VR
5598  {VRF18:D_VRF_0210:D}* {VRF19:D_VRF_0211:D}* {VRF20:D_VRF_0212:D}* {VRF21:D_VRF_0213:D}* {VRF22:D_VRF_0214:D}* {VRF23:D_VRF_0215:D}* {VRF24:D_VRF_0216:D}* {VRF25:D_VR
5599  {VRF26:D_VRF_0218:D}* {VRF27:D_VRF_0219:D}* {VRF28:D_VRF_0220:D}* {VRF29:D_VRF_0221:D}* {VRF30:D_VRF_0222:D}* {VRF31:D_VRF_0223:D}*
5600  [     0x3ff5af7c710]                          LGR     GPR_0225,GPR_0188
5601  [     0x3ff5af7c7f0]                          BRC     NOP(0xf), Label L0067
5602
5603 ============================================================

which is from the call
Class.forName("Animal").isAssignableFrom(Dog.class)

tests from the new changes: http://vmfarm.rtp.raleigh.ibm.com/build_info.php?build_id=98329
@r30shah

@matthewhall2 matthewhall2 requested a review from r30shah July 14, 2025 19:38
@matthewhall2 matthewhall2 force-pushed the assignableFrom_genSuperclassTest branch from f0b0ca1 to 74405a7 Compare July 14, 2025 19:57
Copy link
Contributor

@r30shah r30shah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Previously when performing Class.isAssignableFrom, only the trivial case
of class equality was done inline and any other case relied on a callout
to a C Helper.

With this change, an inlined superclass test is added along with a
castClassCache test, avoiding the C Helper in the most common cases.

Additionally, this change checks for class depth at compile time when
possible to fast-fail when fromClassDepth <=  toClassDepth.

Signed-off-by: Matthew Hall <[email protected]>
@matthewhall2 matthewhall2 force-pushed the assignableFrom_genSuperclassTest branch from 74405a7 to 2a39218 Compare July 14, 2025 20:19
@r30shah
Copy link
Contributor

r30shah commented Jul 14, 2025

jenkins test sanity zlinux jdk8,jdk17,jdk21

@matthewhall2
Copy link
Contributor Author

jdk21 sanity.openjdk fail looks like its #18463

@r30shah
Copy link
Contributor

r30shah commented Jul 15, 2025

jenkins test sanity.openjdk zlinux jdk21

@r30shah
Copy link
Contributor

r30shah commented Jul 15, 2025

All test passes. Merging the changes.

@r30shah r30shah merged commit d78a902 into eclipse-openj9:master Jul 15, 2025
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants