Skip to content

Commit d78a902

Browse files
authored
Merge pull request #20855 from matthewhall2/assignableFrom_genSuperclassTest
Generate inline superclass test for Class.isAssignableFrom on Z
2 parents 705f1cd + 2a39218 commit d78a902

File tree

1 file changed

+158
-36
lines changed

1 file changed

+158
-36
lines changed

runtime/compiler/z/codegen/J9TreeEvaluator.cpp

Lines changed: 158 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3378,7 +3378,7 @@ static void genTestModifierFlags(TR::CodeGenerator *cg, TR::Node *node, TR::Regi
33783378
TR::Instruction *cursor = NULL;
33793379
TR_Debug * debugObj = cg->getDebug();
33803380

3381-
if (!j9classModifierFlagsReg)
3381+
if (NULL == j9classModifierFlagsReg)
33823382
{
33833383
generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, scratchReg,
33843384
generateS390MemoryReference(classReg, offsetof(J9Class, romClass), cg));
@@ -3394,7 +3394,7 @@ static void genTestModifierFlags(TR::CodeGenerator *cg, TR::Node *node, TR::Regi
33943394

33953395
// when user passes in modiferFlags register, it is going to be reused later
33963396
// so we use an RRF instruction to avoid the flags being overwritten by the AND
3397-
if (j9classModifierFlagsReg)
3397+
if (NULL != j9classModifierFlagsReg)
33983398
{
33993399
TR::Register *flagsReg = srm->findOrCreateScratchRegister();
34003400
generateRILInstruction(cg, TR::InstOpCode::IILF, node, flagsReg, flags);
@@ -3407,7 +3407,7 @@ static void genTestModifierFlags(TR::CodeGenerator *cg, TR::Node *node, TR::Regi
34073407
}
34083408

34093409
cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, handleFlagsLabel);
3410-
if (!j9classModifierFlagsReg)
3410+
if (NULL == j9classModifierFlagsReg)
34113411
srm->reclaimScratchRegister(scratchReg);
34123412
}
34133413

@@ -3484,23 +3484,28 @@ static void genSuperclassTest(TR::CodeGenerator *cg, TR::Node *node, TR::Registe
34843484
{
34853485
if (comp->target().is64Bit())
34863486
{
3487-
generateRSInstruction(cg, TR::InstOpCode::SLLG, node, toClassDepthReg, toClassDepthReg, 3);
3487+
cursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, toClassDepthReg, toClassDepthReg, 3);
34883488
}
34893489
else
34903490
{
3491-
generateRSInstruction(cg, TR::InstOpCode::SLL, node, toClassDepthReg, 2);
3491+
cursor = generateRSInstruction(cg, TR::InstOpCode::SLL, node, toClassDepthReg, 2);
34923492
}
34933493

3494-
generateRXInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, toClassReg,
3494+
if (debugObj)
3495+
debugObj->addInstructionComment(cursor, "convert toClasDepth to superclass array offset");
3496+
3497+
cursor = generateRXInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, toClassReg,
34953498
generateS390MemoryReference(superclassArrayReg, toClassDepthReg, 0, cg));
34963499
srm->reclaimScratchRegister(toClassDepthReg);
34973500
}
34983501
else
34993502
{
35003503
int32_t superClassOffset = toClassDepth * TR::Compiler->om.sizeofReferenceAddress();
3501-
generateRXInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, toClassReg,
3504+
cursor = generateRXInstruction(cg, TR::InstOpCode::getCmpOpCode(), node, toClassReg,
35023505
generateS390MemoryReference(superclassArrayReg, superClassOffset, cg));
35033506
}
3507+
if (debugObj)
3508+
debugObj->addInstructionComment(cursor, "check superclass array");
35043509
srm->reclaimScratchRegister(superclassArrayReg);
35053510
}
35063511

@@ -11667,8 +11672,6 @@ J9::Z::TreeEvaluator::VMarrayCheckEvaluator(TR::Node *node, TR::CodeGenerator *c
1166711672
return 0;
1166811673
}
1166911674

11670-
/////////////////////////////////////////////////////////////////////////////////
11671-
/////////////////////////////////////////////////////////////////////////////////
1167211675
static bool inlineIsAssignableFrom(TR::Node *node, TR::CodeGenerator *cg)
1167311676
{
1167411677
static char *disable = feGetEnv("TR_disableInlineIsAssignableFrom");
@@ -11809,53 +11812,172 @@ static bool inlineIsAssignableFrom(TR::Node *node, TR::CodeGenerator *cg)
1180911812
return true;
1181011813
}
1181111814

11815+
static TR::SymbolReference *getClassSymRefAndDepth(TR::Node *classNode, TR::Compilation *comp, int32_t &classDepth)
11816+
{
11817+
classDepth = -1;
11818+
TR::SymbolReference *classSymRef = NULL;
11819+
const TR::ILOpCodes opcode = classNode->getOpCodeValue();
11820+
bool isClassNodeLoadAddr = opcode == TR::loadaddr;
11821+
11822+
// getting the symbol ref
11823+
if (isClassNodeLoadAddr)
11824+
{
11825+
classSymRef = classNode->getSymbolReference();
11826+
}
11827+
else if (opcode == TR::aloadi)
11828+
{
11829+
// recognizedCallTransformer adds another layer of aloadi
11830+
while (classNode->getOpCodeValue() == TR::aloadi && classNode->getFirstChild()->getOpCodeValue() == TR::aloadi)
11831+
{
11832+
classNode = classNode->getFirstChild();
11833+
}
11834+
11835+
if (classNode->getOpCodeValue() == TR::aloadi && classNode->getFirstChild()->getOpCodeValue() == TR::loadaddr)
11836+
{
11837+
classSymRef = classNode->getFirstChild()->getSymbolReference();
11838+
}
11839+
}
11840+
11841+
// the class node being <loadaddr> is an edge case - likely will not happen since we shouldn't see
11842+
// Class.isAssignableFrom on classes known at compile (javac) time, but still possible.
11843+
if (!isClassNodeLoadAddr && (classNode->getOpCodeValue() != TR::aloadi ||
11844+
classNode->getSymbolReference() != comp->getSymRefTab()->findJavaLangClassFromClassSymbolRef() ||
11845+
classNode->getFirstChild()->getOpCodeValue() != TR::loadaddr))
11846+
{
11847+
return classSymRef; // cannot find class depth
11848+
}
11849+
11850+
TR::Node *classRef = isClassNodeLoadAddr ? classNode : classNode->getFirstChild();
11851+
TR::SymbolReference *symRef = classRef->getOpCode().hasSymbolReference() ? classRef->getSymbolReference() : NULL;
11852+
11853+
if (symRef != NULL && !symRef->isUnresolved())
11854+
{
11855+
TR::StaticSymbol *classSym = symRef->getSymbol()->getStaticSymbol();
11856+
TR_OpaqueClassBlock *clazz = (classSym != NULL) ? (TR_OpaqueClassBlock *) classSym->getStaticAddress() : NULL;
11857+
if (clazz != NULL)
11858+
classDepth = static_cast<int32_t>(TR::Compiler->cls.classDepthOf(clazz));
11859+
}
11860+
11861+
return classSymRef;
11862+
}
11863+
1181211864
TR::Register *J9::Z::TreeEvaluator::inlineCheckAssignableFromEvaluator(TR::Node *node, TR::CodeGenerator *cg)
1181311865
{
11814-
TR::Register *fromClassReg = cg->evaluate(node->getFirstChild());
11815-
TR::Register *toClassReg = cg->evaluate(node->getSecondChild());
11866+
TR::Compilation *comp = cg->comp();
11867+
// recognizedCallTransformer swaps the args - caller class obj is the second argument after the transformation
11868+
TR::Node *fromClass = node->getFirstChild();
11869+
TR::Node *toClass = node->getSecondChild();
11870+
TR::Register *fromClassReg = cg->evaluate(fromClass);
11871+
TR::Register *toClassReg = cg->evaluate(toClass);
1181611872

11817-
TR::Register *resultReg = cg->allocateRegister();
1181811873
TR::LabelSymbol *helperCallLabel = generateLabelSymbol(cg);
1181911874
TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);
11820-
TR::LabelSymbol *successLabel = generateLabelSymbol(cg);
11821-
11875+
TR::LabelSymbol *failLabel = generateLabelSymbol(cg);
11876+
TR::LabelSymbol *successLabel = doneLabel;
1182211877
TR::LabelSymbol* cFlowRegionStart = generateLabelSymbol(cg);
11823-
generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);
11824-
cFlowRegionStart->setStartInternalControlFlow();
1182511878

11826-
/*
11827-
* check for class equality
11828-
* if equal, we are done. If not, fall through to helper call
11829-
*/
11830-
generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, toClassReg, fromClassReg, TR::InstOpCode::COND_BE, successLabel, false, false);
11831-
11832-
/*
11833-
* TODO: add inlined tests (SuperclassTest, cast class cache, etc)
11834-
* Inlined tests will be used when possible, or will jump to the OOL section
11835-
* and perform the tests using the CHelper when not possible
11836-
*/
11879+
TR_S390ScratchRegisterManager *srm = cg->generateScratchRegisterManager(2);
1183711880

11838-
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, helperCallLabel);
11881+
// create OOL section here to have access to the result register to load initial result
1183911882
TR_S390OutOfLineCodeSection *outlinedSlowPath = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(helperCallLabel, doneLabel, cg);
1184011883
cg->getS390OutOfLineCodeSectionList().push_front(outlinedSlowPath);
1184111884
outlinedSlowPath->swapInstructionListsWithCompilation();
11842-
1184311885
generateS390LabelInstruction(cg, TR::InstOpCode::label, node, helperCallLabel);
11844-
resultReg = TR::TreeEvaluator::performCall(node, false, cg);
11845-
11886+
TR::Register *resultReg = TR::TreeEvaluator::performCall(node, false, cg);
1184611887
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, doneLabel); // exit OOL section
1184711888
outlinedSlowPath->swapInstructionListsWithCompilation();
1184811889

11849-
generateS390LabelInstruction(cg, TR::InstOpCode::label, node, successLabel);
11850-
generateRIInstruction(cg, TR::InstOpCode::getLoadHalfWordImmOpCode(), node, resultReg, 1);
11890+
// load with initial result of true
11891+
generateRIInstruction(cg, TR::InstOpCode::LHI, node, resultReg, 1);
11892+
generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);
11893+
cFlowRegionStart->setStartInternalControlFlow();
11894+
TR_Debug * debugObj = cg->getDebug();
11895+
TR::Instruction *cursor = NULL;
11896+
11897+
if (comp->getOption(TR_TraceCG))
11898+
traceMsg(comp,"%s: Emitting Class Equality Test\n",node->getOpCode().getName());
11899+
// 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);
11901+
cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, toClassReg, fromClassReg, TR::InstOpCode::COND_BE, successLabel, false, false);
11902+
if (debugObj)
11903+
debugObj->addInstructionComment(cursor, "class equality test");
11904+
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/ClassEqualityTest/Fail", comp->signature()), 1, TR::DebugCounter::Undetermined);
11905+
11906+
int32_t toClassDepth = -1;
11907+
TR::SymbolReference *toClassSymRef = getClassSymRefAndDepth(toClass, comp, toClassDepth);
11908+
bool fastFail = false;
11909+
if (comp->getOption(TR_TraceCG))
11910+
traceMsg(comp,"%s: toClassSymRef is %s\n",node->getOpCode().getName(), NULL == toClassSymRef ? "null" : "non-null");
11911+
if (NULL != toClassSymRef && comp->getOption(TR_TraceCG))
11912+
traceMsg(comp,"%s: toClass is %s\n",node->getOpCode().getName(), toClassSymRef->isClassInterface(comp) ? "an interface" : "not an interface");
11913+
if ((NULL != toClassSymRef) && !toClassSymRef->isClassInterface(comp))
11914+
{
11915+
int32_t fromClassDepth = -1;
11916+
TR::SymbolReference *fromClassSymRef = getClassSymRefAndDepth(fromClass, comp, fromClassDepth);
11917+
if (comp->getOption(TR_TraceCG))
11918+
traceMsg(comp,"%s: fromClassSymRef is %s\n",node->getOpCode().getName(), NULL == toClassSymRef ? "null" : "non-null");
11919+
if ((NULL != fromClassSymRef) && !fromClassSymRef->isClassInterface(comp))
11920+
{
11921+
if (toClassDepth > -1 && fromClassDepth > -1 && toClassDepth > fromClassDepth)
11922+
{
11923+
cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, failLabel);
11924+
if (debugObj)
11925+
{
11926+
debugObj->addInstructionComment(cursor, "toclass depth > fromClass depth at compile time - fast fail");
11927+
}
11928+
}
11929+
fastFail = true;
11930+
}
11931+
}
11932+
11933+
if (!fastFail)
11934+
{
11935+
// castClassCache test
11936+
if ((NULL != toClassSymRef) && comp->getOption(TR_TraceCG))
11937+
traceMsg(comp,"%s: toclass is %s\n",node->getOpCode().getName(), toClassSymRef->isClassAbstract(comp) ? "abstract" : "non-abstract");
11938+
if ((NULL == toClassSymRef) || !toClassSymRef->isClassAbstract(comp))
11939+
{
11940+
if (comp->getOption(TR_TraceCG))
11941+
traceMsg(comp,"%s: Emitting CastClassCacheTest\n",node->getOpCode().getName());
11942+
TR::Register *castClassCacheReg = srm->findOrCreateScratchRegister();
11943+
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/Cache", comp->signature()), 1, TR::DebugCounter::Undetermined);
11944+
generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, castClassCacheReg,
11945+
generateS390MemoryReference(fromClassReg, offsetof(J9Class, castClassCache), cg));
11946+
cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, castClassCacheReg, toClassReg, TR::InstOpCode::COND_BE, successLabel, false, false);
11947+
if (debugObj)
11948+
debugObj->addInstructionComment(cursor, "castclass cache test");
11949+
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/Cache/Fail", comp->signature()), 1, TR::DebugCounter::Undetermined);
11950+
srm->reclaimScratchRegister(castClassCacheReg);
11951+
}
1185111952

11852-
TR::RegisterDependencyConditions* deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 3, cg);
11953+
// superclass test
11954+
if((NULL == toClassSymRef) || !toClassSymRef->isClassInterface(comp))
11955+
{
11956+
const int32_t flags = (J9AccInterface | J9AccClassArray);
11957+
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/SuperclassTest", comp->signature()), 1, TR::DebugCounter::Undetermined);
11958+
if (toClassDepth == -1)
11959+
{
11960+
genTestModifierFlags(cg, node, toClassReg, toClassDepth, helperCallLabel, srm, flags);
11961+
}
11962+
genSuperclassTest(cg, node, toClassReg, toClassDepth, fromClassReg, failLabel, srm);
11963+
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);
11965+
}
11966+
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, helperCallLabel);
11967+
}
11968+
11969+
srm->stopUsingRegisters();
11970+
generateS390LabelInstruction(cg, TR::InstOpCode::label, node, failLabel);
11971+
generateRIInstruction(cg, TR::InstOpCode::LHI, node, resultReg, 0);
11972+
11973+
TR::RegisterDependencyConditions* deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 3 + srm->numAvailableRegisters(), cg);
11974+
srm->addScratchRegistersToDependencyList(deps);
11975+
deps->addPostCondition(resultReg, TR::RealRegister::AssignAny);
1185311976
deps->addPostCondition(fromClassReg, TR::RealRegister::AssignAny);
1185411977
deps->addPostConditionIfNotAlreadyInserted(toClassReg, TR::RealRegister::AssignAny);
11855-
deps->addPostCondition(resultReg, TR::RealRegister::AssignAny);
11856-
1185711978
generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);
1185811979
doneLabel->setEndInternalControlFlow();
11980+
1185911981
node->setRegister(resultReg);
1186011982
return resultReg;
1186111983
}

0 commit comments

Comments
 (0)