Skip to content

Commit 72886b0

Browse files
committed
Add inlined itable walk for Class.isAssignableFrom on Z
For the interface case, skips the superclass tests and goes straight to an inlined itable walk which is guarenteed to give a result. Signed-off-by: Matthew Hall <[email protected]>
1 parent 410dece commit 72886b0

File tree

1 file changed

+70
-9
lines changed

1 file changed

+70
-9
lines changed

runtime/compiler/z/codegen/J9TreeEvaluator.cpp

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11861,6 +11861,51 @@ static TR::SymbolReference *getClassSymRefAndDepth(TR::Node *classNode, TR::Comp
1186111861
return classSymRef;
1186211862
}
1186311863

11864+
static void genITableTest(TR::Node *node, TR::CodeGenerator *cg, TR_S390ScratchRegisterManager *srm, TR::Register *fromClassReg, TR::Register *toClassReg, TR::LabelSymbol *successLabel, TR::LabelSymbol *failLabel)
11865+
{
11866+
TR::Compilation *comp = cg->comp();
11867+
TR_Debug * debugObj = cg->getDebug();
11868+
bool traceCG = comp->getOption(TR_TraceCG);
11869+
TR::LabelSymbol *cacheCastClassLabel = generateLabelSymbol(cg);
11870+
TR::LabelSymbol *startWalkLabel = generateLabelSymbol(cg);
11871+
11872+
TR::Register *iTableReg = srm->findOrCreateScratchRegister();
11873+
// lastITable Test
11874+
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/interfaceTest/lastITable"), 1, TR::DebugCounter::Undetermined);
11875+
TR::Instruction *cursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, iTableReg,
11876+
generateS390MemoryReference(fromClassReg, offsetof(J9Class, lastITable), cg));
11877+
// last itable is never null
11878+
generateRXInstruction(cg, TR::InstOpCode::getCmpLogicalOpCode(), node, toClassReg,
11879+
generateS390MemoryReference(iTableReg, offsetof(J9ITable, interfaceClass), cg));
11880+
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, successLabel);
11881+
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/interfaceTest/lastITable/fail"), 1, TR::DebugCounter::Undetermined);
11882+
// Itable Test
11883+
cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, startWalkLabel);
11884+
cursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, iTableReg,
11885+
generateS390MemoryReference(fromClassReg, offsetof(J9Class, iTable), cg));
11886+
11887+
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/interfaceTest/ITableWalk"), 1, TR::DebugCounter::Undetermined);
11888+
11889+
TR::LabelSymbol *startLoop = generateLabelSymbol(cg);
11890+
cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, startLoop);
11891+
if (debugObj && traceCG)
11892+
debugObj->addInstructionComment(cursor, "--> Start of iTable walk");
11893+
11894+
generateRRInstruction(cg, TR::InstOpCode::getLoadTestRegOpCode(), node, iTableReg, iTableReg);
11895+
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, failLabel);
11896+
generateRXInstruction(cg, TR::InstOpCode::getCmpLogicalOpCode(), node, toClassReg,
11897+
generateS390MemoryReference(iTableReg, offsetof(J9ITable, interfaceClass), cg));
11898+
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, successLabel);
11899+
generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, iTableReg,
11900+
generateS390MemoryReference(iTableReg, offsetof(J9ITable, next), cg));
11901+
cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, startLoop);
11902+
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/interfaceTest/ITableWalk/fail"), 1, TR::DebugCounter::Undetermined);
11903+
if (debugObj && traceCG)
11904+
debugObj->addInstructionComment(cursor, "to start of loop");
11905+
11906+
srm->reclaimScratchRegister(iTableReg);
11907+
}
11908+
1186411909
TR::Register *J9::Z::TreeEvaluator::inlineCheckAssignableFromEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1186511910
{
1186611911
TR::Compilation *comp = cg->comp();
@@ -11875,6 +11920,7 @@ TR::Register *J9::Z::TreeEvaluator::inlineCheckAssignableFromEvaluator(TR::Node
1187511920
TR::LabelSymbol *failLabel = generateLabelSymbol(cg);
1187611921
TR::LabelSymbol *successLabel = doneLabel;
1187711922
TR::LabelSymbol* cFlowRegionStart = generateLabelSymbol(cg);
11923+
TR::LabelSymbol* ITableTestLabel = generateLabelSymbol(cg);
1187811924

1187911925
TR_S390ScratchRegisterManager *srm = cg->generateScratchRegisterManager(2);
1188011926

@@ -11897,11 +11943,11 @@ TR::Register *J9::Z::TreeEvaluator::inlineCheckAssignableFromEvaluator(TR::Node
1189711943
if (comp->getOption(TR_TraceCG))
1189811944
traceMsg(comp,"%s: Emitting Class Equality Test\n",node->getOpCode().getName());
1189911945
// for isAssignableFrom we can always generate the class equality test since both arguments are classes
11900-
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/ClassEqualityTest", comp->signature()), 1, TR::DebugCounter::Undetermined);
11946+
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/ClassEqualityTest"), 1, TR::DebugCounter::Undetermined);
1190111947
cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, toClassReg, fromClassReg, TR::InstOpCode::COND_BE, successLabel, false, false);
1190211948
if (debugObj)
1190311949
debugObj->addInstructionComment(cursor, "class equality test");
11904-
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/ClassEqualityTest/Fail", comp->signature()), 1, TR::DebugCounter::Undetermined);
11950+
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/ClassEqualityTest/Fail"), 1, TR::DebugCounter::Undetermined);
1190511951

1190611952
int32_t toClassDepth = -1;
1190711953
TR::SymbolReference *toClassSymRef = getClassSymRefAndDepth(toClass, comp, toClassDepth);
@@ -11940,30 +11986,45 @@ TR::Register *J9::Z::TreeEvaluator::inlineCheckAssignableFromEvaluator(TR::Node
1194011986
if (comp->getOption(TR_TraceCG))
1194111987
traceMsg(comp,"%s: Emitting CastClassCacheTest\n",node->getOpCode().getName());
1194211988
TR::Register *castClassCacheReg = srm->findOrCreateScratchRegister();
11943-
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/Cache", comp->signature()), 1, TR::DebugCounter::Undetermined);
11989+
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/Cache"), 1, TR::DebugCounter::Undetermined);
1194411990
generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, castClassCacheReg,
1194511991
generateS390MemoryReference(fromClassReg, offsetof(J9Class, castClassCache), cg));
1194611992
cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, castClassCacheReg, toClassReg, TR::InstOpCode::COND_BE, successLabel, false, false);
1194711993
if (debugObj)
1194811994
debugObj->addInstructionComment(cursor, "castclass cache test");
11949-
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/Cache/Fail", comp->signature()), 1, TR::DebugCounter::Undetermined);
11995+
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/Cache/Fail"), 1, TR::DebugCounter::Undetermined);
1195011996
srm->reclaimScratchRegister(castClassCacheReg);
1195111997
}
1195211998

1195311999
// superclass test
1195412000
if((NULL == toClassSymRef) || !toClassSymRef->isClassInterface(comp))
1195512001
{
11956-
const int32_t flags = (J9AccInterface | J9AccClassArray);
11957-
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/SuperclassTest", comp->signature()), 1, TR::DebugCounter::Undetermined);
12002+
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/SuperclassTest"), 1, TR::DebugCounter::Undetermined);
1195812003
if (toClassDepth == -1)
1195912004
{
11960-
genTestModifierFlags(cg, node, toClassReg, toClassDepth, helperCallLabel, srm, flags);
12005+
if (feGetEnv("enableInlineItableWalkForIsAssignableFrom")) {
12006+
TR::Register *modifierReg = srm->findOrCreateScratchRegister();
12007+
generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, modifierReg,
12008+
generateS390MemoryReference(toClassReg, offsetof(J9Class, classDepthAndFlags), cg));
12009+
genTestModifierFlags(cg, node, toClassReg, toClassDepth, ITableTestLabel, srm, J9AccInterface, modifierReg);
12010+
genTestModifierFlags(cg, node, toClassReg, toClassDepth, helperCallLabel, srm, J9AccClassArray, modifierReg);
12011+
srm->reclaimScratchRegister(modifierReg);
12012+
} else {
12013+
genTestModifierFlags(cg, node, toClassReg, toClassDepth, helperCallLabel, srm, J9AccInterface | J9AccClassArray);
12014+
}
1196112015
}
1196212016
genSuperclassTest(cg, node, toClassReg, toClassDepth, fromClassReg, failLabel, srm);
1196312017
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, successLabel);
11964-
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/SuperclassTest/Fail", comp->signature()), 1, TR::DebugCounter::Undetermined);
12018+
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/SuperclassTest/Fail"), 1, TR::DebugCounter::Undetermined);
12019+
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, helperCallLabel);
12020+
}
12021+
// we don't generate ITable test if we know we don't have an interface
12022+
if ((toClassDepth == -1) || (NULL == toClassSymRef || toClassSymRef->isClassInterface(comp)))
12023+
{
12024+
generateS390LabelInstruction(cg, TR::InstOpCode::label, node, ITableTestLabel);
12025+
// no need for helper if we fail interface test - we known the cast class is an interface
12026+
genITableTest(node, cg, srm, fromClassReg, toClassReg, doneLabel, failLabel);
1196512027
}
11966-
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, helperCallLabel);
1196712028
}
1196812029

1196912030
srm->stopUsingRegisters();

0 commit comments

Comments
 (0)