Skip to content

Commit cf5b708

Browse files
committed
Update isAssignableFrom to use C Helper and Inline Checks in P
Update the Class.isAssignableFrom Method to use various inline check, and fall back to the C helper rather than the slower JNI call, on Power.
1 parent 91cec0d commit cf5b708

File tree

2 files changed

+201
-1
lines changed

2 files changed

+201
-1
lines changed

runtime/compiler/p/codegen/J9CodeGenerator.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ class OMR_EXTENSIBLE CodeGenerator : public J9::CodeGenerator
115115

116116
// See J9::CodeGenerator::guaranteesResolvedDirectDispatchForSVM
117117
bool guaranteesResolvedDirectDispatchForSVM() { return true; }
118-
};
119118

119+
bool supportsInliningOfIsAssignableFrom() {return true;}
120+
};
120121
}
121122

122123
}

runtime/compiler/p/codegen/J9TreeEvaluator.cpp

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9807,6 +9807,195 @@ static TR::Register *inlineAtomicOperation(TR::Node *node, TR::CodeGenerator *cg
98079807
return resultReg;
98089808
}
98099809

9810+
// duplicate from the static method in Z
9811+
static TR::SymbolReference *getClassSymRefAndDepth(TR::Node *classNode,
9812+
TR::Compilation *comp, int32_t &classDepth)
9813+
{
9814+
classDepth = -1;
9815+
TR::SymbolReference *classSymRef = NULL;
9816+
const TR::ILOpCodes opcode = classNode->getOpCodeValue();
9817+
bool isClassNodeLoadAddr = opcode == TR::loadaddr;
9818+
9819+
// getting the symbol ref
9820+
if (isClassNodeLoadAddr)
9821+
{
9822+
classSymRef = classNode->getSymbolReference();
9823+
}
9824+
else if (opcode == TR::aloadi)
9825+
{
9826+
// recognizedCallTransformer adds another layer of aloadi
9827+
while (classNode->getOpCodeValue() == TR::aloadi && classNode->getFirstChild()->getOpCodeValue() == TR::aloadi)
9828+
{
9829+
classNode = classNode->getFirstChild();
9830+
}
9831+
9832+
if (classNode->getOpCodeValue() == TR::aloadi && classNode->getFirstChild()->getOpCodeValue() == TR::loadaddr)
9833+
{
9834+
classSymRef = classNode->getFirstChild()->getSymbolReference();
9835+
}
9836+
}
9837+
9838+
// the class node being <loadaddr> is an edge case - likely will not happen since we shouldn't see
9839+
// Class.isAssignableFrom on classes known at compile (javac) time, but still possible.
9840+
if (!isClassNodeLoadAddr && (classNode->getOpCodeValue() != TR::aloadi ||
9841+
classNode->getSymbolReference() != comp->getSymRefTab()->findJavaLangClassFromClassSymbolRef() ||
9842+
classNode->getFirstChild()->getOpCodeValue() != TR::loadaddr))
9843+
{
9844+
return classSymRef; // cannot find class depth
9845+
}
9846+
9847+
TR::Node *classRef = isClassNodeLoadAddr ? classNode : classNode->getFirstChild();
9848+
TR::SymbolReference *symRef = classRef->getOpCode().hasSymbolReference() ? classRef->getSymbolReference() : NULL;
9849+
9850+
if (symRef != NULL && !symRef->isUnresolved())
9851+
{
9852+
TR::StaticSymbol *classSym = symRef->getSymbol()->getStaticSymbol();
9853+
TR_OpaqueClassBlock *clazz = (classSym != NULL) ? (TR_OpaqueClassBlock *) classSym->getStaticAddress() : NULL;
9854+
if (clazz != NULL)
9855+
classDepth = static_cast<int32_t>(TR::Compiler->cls.classDepthOf(clazz));
9856+
}
9857+
9858+
return classSymRef;
9859+
}
9860+
9861+
static TR::Register *inlineCheckAssignableFromEvaluator(TR::Node *node, TR::CodeGenerator *cg)
9862+
{
9863+
TR::Compilation *comp = cg->comp();
9864+
9865+
// original form: toClass.isAssignableFrom(fromClass)
9866+
TR::Node *fromClass = node->getFirstChild();
9867+
TR::Node *toClass = node->getSecondChild();
9868+
9869+
TR::Register *fromClassReg = cg->evaluate(fromClass);
9870+
TR::Register *toClassReg = cg->evaluate(toClass);
9871+
9872+
TR::Register *cacheReg = cg->allocateRegister();
9873+
9874+
TR::Register *condReg = cg->allocateRegister(TR_CCR);
9875+
9876+
TR::Register *resultReg = cg->allocateRegister();
9877+
9878+
TR::LabelSymbol *startLabel = generateLabelSymbol(cg);
9879+
TR::LabelSymbol *oolJumpLabel = generateLabelSymbol(cg);
9880+
TR::LabelSymbol *endLabel = generateLabelSymbol(cg);
9881+
9882+
TR::LabelSymbol *failLabel = generateLabelSymbol(cg);
9883+
TR::LabelSymbol *successLabel = endLabel;
9884+
9885+
TR_PPCScratchRegisterManager *srm = cg->generateScratchRegisterManager();
9886+
9887+
// jump to the out of line code if inlined code cannot handle it
9888+
TR_PPCOutOfLineCodeSection *outlinedHelperCall = new (cg->trHeapMemory())
9889+
TR_PPCOutOfLineCodeSection(node, TR::icall, resultReg, oolJumpLabel, endLabel, cg);
9890+
cg->getPPCOutOfLineCodeSectionList().push_front(outlinedHelperCall);
9891+
9892+
generateLabelInstruction(cg, TR::InstOpCode::label, node, startLabel);
9893+
startLabel->setStartInternalControlFlow();
9894+
9895+
// Checking at compile time if possible.
9896+
int32_t toClassDepth = -1;
9897+
TR::SymbolReference *toClassSymRef = getClassSymRefAndDepth(toClass, comp, toClassDepth);
9898+
bool fastFail = false;
9899+
if (comp->getOption(TR_TraceCG))
9900+
{
9901+
traceMsg(comp, "%s: toClassSymRef is %s\n", node->getOpCode().getName(),
9902+
NULL == toClassSymRef ? "null" : "non-null");
9903+
if (toClassSymRef)
9904+
{
9905+
traceMsg(comp, "%s: toClass is %s, %s, %s\n", node->getOpCode().getName(),
9906+
toClassSymRef->isClassInterface(comp) ? "an interface" : "not an interface",
9907+
toClassSymRef->isClassAbstract(comp) ? "abstract" : "non-abstract");
9908+
}
9909+
}
9910+
if ((NULL != toClassSymRef) && !toClassSymRef->isClassInterface(comp))
9911+
{
9912+
int32_t fromClassDepth = -1;
9913+
TR::SymbolReference *fromClassSymRef = getClassSymRefAndDepth(fromClass, comp, fromClassDepth);
9914+
if (comp->getOption(TR_TraceCG))
9915+
{
9916+
traceMsg(comp, "%s: fromClassSymRef is %s\n", node->getOpCode().getName(),
9917+
NULL == fromClassSymRef ? "null" : "non-null");
9918+
if (fromClassSymRef)
9919+
{
9920+
traceMsg(comp, "%s: fromClass is %s, %s, %s\n", node->getOpCode().getName(),
9921+
fromClassSymRef->isClassInterface(comp) ? "an interface" : "not an interface",
9922+
fromClassSymRef->isClassAbstract(comp) ? "abstract" : "non-abstract");
9923+
}
9924+
}
9925+
if ((NULL != fromClassSymRef) && !fromClassSymRef->isClassInterface(comp))
9926+
{
9927+
if (comp->getOption(TR_TraceCG))
9928+
traceMsg(comp, "depths %d %d\n", toClassDepth, fromClassDepth);
9929+
if (toClassDepth > -1 && fromClassDepth > -1 && toClassDepth > fromClassDepth)
9930+
{
9931+
// fall into the failLabel
9932+
fastFail = true;
9933+
}
9934+
}
9935+
}
9936+
9937+
if (!fastFail) // generate the inline tests if we cannot figure it out on compile time
9938+
{
9939+
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0x777); // eyecatcher
9940+
// default to success
9941+
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 1);
9942+
9943+
// equality test
9944+
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, fromClassReg, toClassReg);
9945+
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, successLabel, condReg);
9946+
9947+
// castClassCache test
9948+
if ((NULL == toClassSymRef) || (!toClassSymRef->isClassAbstract(comp)))
9949+
{
9950+
generateTrg1MemInstruction(cg,TR::InstOpCode::Op_load, node, cacheReg,
9951+
TR::MemoryReference::createWithDisplacement(cg, fromClassReg,
9952+
offsetof(J9Class, castClassCache), TR::Compiler->om.sizeofReferenceAddress()));
9953+
generateTrg1Src2Instruction(cg,TR::InstOpCode::Op_cmpl, node, condReg, cacheReg, toClassReg);
9954+
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, successLabel, condReg);
9955+
}
9956+
9957+
// superClass test
9958+
if ((NULL == toClassSymRef) || (!toClassSymRef->isClassInterface(comp)))
9959+
{
9960+
genInstanceOfOrCheckCastSuperClassTest(node, condReg, fromClassReg, toClassReg,
9961+
toClassDepth, oolJumpLabel, srm, cg);
9962+
generateConditionalBranchInstruction(cg, TR::InstOpCode::beq, node, successLabel, condReg);
9963+
}
9964+
// fallback to the helper
9965+
generateLabelInstruction(cg, TR::InstOpCode::b, node, oolJumpLabel);
9966+
}
9967+
9968+
generateLabelInstruction(cg, TR::InstOpCode::label, node, failLabel);
9969+
generateTrg1ImmInstruction(cg, TR::InstOpCode::li, node, resultReg, 0);
9970+
9971+
srm->stopUsingRegisters();
9972+
cg->stopUsingRegister(fromClassReg);
9973+
cg->stopUsingRegister(toClassReg);
9974+
cg->stopUsingRegister(cacheReg);
9975+
9976+
const short numReg = 4 + srm->numAvailableRegisters();
9977+
TR::RegisterDependencyConditions *dependencies =
9978+
new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0,
9979+
numReg, cg->trMemory());
9980+
9981+
srm->addScratchRegistersToDependencyList(dependencies);
9982+
9983+
dependencies->addPostCondition(fromClassReg, TR::RealRegister::NoReg);
9984+
dependencies->addPostCondition(toClassReg, TR::RealRegister::NoReg);
9985+
dependencies->addPostCondition(cacheReg, TR::RealRegister::NoReg);
9986+
dependencies->addPostCondition(resultReg, TR::RealRegister::NoReg);
9987+
9988+
for (int i = 0; i < numReg; i++) {
9989+
dependencies->getPostConditions()->getRegisterDependency(i)->setExcludeGPR0();
9990+
}
9991+
9992+
generateDepLabelInstruction(cg, TR::InstOpCode::label, node, endLabel, dependencies);
9993+
9994+
endLabel->setEndInternalControlFlow();
9995+
node->setRegister(resultReg);
9996+
return resultReg;
9997+
}
9998+
98109999
static TR::Register *inlineConcurrentLinkedQueueTMOffer(TR::Node *node, TR::CodeGenerator *cg)
981110000
{
981210001
TR::Compilation *comp = cg->comp();
@@ -12495,6 +12684,16 @@ J9::Power::CodeGenerator::inlineDirectCall(TR::Node *node, TR::Register *&result
1249512684
{
1249612685
return true;
1249712686
}
12687+
else if (node->getSymbolReference()->getReferenceNumber() == TR_checkAssignable)
12688+
{
12689+
if (comp->getOption(TR_TraceCG))
12690+
{
12691+
printf("LkL inlining\n");
12692+
resultReg = inlineCheckAssignableFromEvaluator(node, cg);
12693+
return true;
12694+
}
12695+
return false;
12696+
}
1249812697
else if (methodSymbol)
1249912698
{
1250012699
bool disableCASInlining = !cg->getSupportsInlineUnsafeCompareAndSet();

0 commit comments

Comments
 (0)