Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 71 additions & 9 deletions runtime/compiler/z/codegen/J9TreeEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11861,9 +11861,55 @@ static TR::SymbolReference *getClassSymRefAndDepth(TR::Node *classNode, TR::Comp
return classSymRef;
}

static void genITableTest(TR::Node *node, TR::CodeGenerator *cg, TR_S390ScratchRegisterManager *srm, TR::Register *fromClassReg, TR::Register *toClassReg, TR::LabelSymbol *successLabel, TR::LabelSymbol *failLabel)
{
TR::Compilation *comp = cg->comp();
TR_Debug * debugObj = cg->getDebug();
bool traceCG = comp->getOption(TR_TraceCG);
TR::LabelSymbol *cacheCastClassLabel = generateLabelSymbol(cg);
TR::LabelSymbol *startWalkLabel = generateLabelSymbol(cg);

TR::Register *iTableReg = srm->findOrCreateScratchRegister();
// lastITable Test
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/interfaceTest/lastITable"), 1, TR::DebugCounter::Undetermined);
TR::Instruction *cursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, iTableReg,
generateS390MemoryReference(fromClassReg, offsetof(J9Class, lastITable), cg));
// last itable is never null
generateRXInstruction(cg, TR::InstOpCode::getCmpLogicalOpCode(), node, toClassReg,
generateS390MemoryReference(iTableReg, offsetof(J9ITable, interfaceClass), cg));
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, successLabel);
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/interfaceTest/lastITable/fail"), 1, TR::DebugCounter::Undetermined);
// Itable Test
cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, startWalkLabel);
cursor = generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, iTableReg,
generateS390MemoryReference(fromClassReg, offsetof(J9Class, iTable), cg));

cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/interfaceTest/ITableWalk"), 1, TR::DebugCounter::Undetermined);

TR::LabelSymbol *startLoop = generateLabelSymbol(cg);
cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, startLoop);
if (debugObj && traceCG)
debugObj->addInstructionComment(cursor, "--> Start of iTable walk");

generateRRInstruction(cg, TR::InstOpCode::getLoadTestRegOpCode(), node, iTableReg, iTableReg);
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, failLabel);
generateRXInstruction(cg, TR::InstOpCode::getCmpLogicalOpCode(), node, toClassReg,
generateS390MemoryReference(iTableReg, offsetof(J9ITable, interfaceClass), cg));
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, successLabel);
generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, iTableReg,
generateS390MemoryReference(iTableReg, offsetof(J9ITable, next), cg));
cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, startLoop);
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/interfaceTest/ITableWalk/fail"), 1, TR::DebugCounter::Undetermined);
if (debugObj && traceCG)
debugObj->addInstructionComment(cursor, "to start of loop");

srm->reclaimScratchRegister(iTableReg);
}

TR::Register *J9::Z::TreeEvaluator::inlineCheckAssignableFromEvaluator(TR::Node *node, TR::CodeGenerator *cg)
{
TR::Compilation *comp = cg->comp();
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromPath/(%s)", comp->signature()), 1, TR::DebugCounter::Undetermined);
// recognizedCallTransformer swaps the args - caller class obj is the second argument after the transformation
TR::Node *fromClass = node->getFirstChild();
TR::Node *toClass = node->getSecondChild();
Expand All @@ -11875,6 +11921,7 @@ TR::Register *J9::Z::TreeEvaluator::inlineCheckAssignableFromEvaluator(TR::Node
TR::LabelSymbol *failLabel = generateLabelSymbol(cg);
TR::LabelSymbol *successLabel = doneLabel;
TR::LabelSymbol* cFlowRegionStart = generateLabelSymbol(cg);
TR::LabelSymbol* ITableTestLabel = generateLabelSymbol(cg);

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

Expand All @@ -11897,11 +11944,11 @@ TR::Register *J9::Z::TreeEvaluator::inlineCheckAssignableFromEvaluator(TR::Node
if (comp->getOption(TR_TraceCG))
traceMsg(comp,"%s: Emitting Class Equality Test\n",node->getOpCode().getName());
// for isAssignableFrom we can always generate the class equality test since both arguments are classes
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/ClassEqualityTest", comp->signature()), 1, TR::DebugCounter::Undetermined);
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/ClassEqualityTest"), 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");
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/ClassEqualityTest/Fail", comp->signature()), 1, TR::DebugCounter::Undetermined);
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/ClassEqualityTest/Fail"), 1, TR::DebugCounter::Undetermined);

int32_t toClassDepth = -1;
TR::SymbolReference *toClassSymRef = getClassSymRefAndDepth(toClass, comp, toClassDepth);
Expand Down Expand Up @@ -11940,30 +11987,45 @@ TR::Register *J9::Z::TreeEvaluator::inlineCheckAssignableFromEvaluator(TR::Node
if (comp->getOption(TR_TraceCG))
traceMsg(comp,"%s: Emitting CastClassCacheTest\n",node->getOpCode().getName());
TR::Register *castClassCacheReg = srm->findOrCreateScratchRegister();
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/Cache", comp->signature()), 1, TR::DebugCounter::Undetermined);
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/Cache"), 1, TR::DebugCounter::Undetermined);
generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, castClassCacheReg,
generateS390MemoryReference(fromClassReg, offsetof(J9Class, castClassCache), cg));
cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, castClassCacheReg, toClassReg, TR::InstOpCode::COND_BE, successLabel, false, false);
if (debugObj)
debugObj->addInstructionComment(cursor, "castclass cache test");
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/Cache/Fail", comp->signature()), 1, TR::DebugCounter::Undetermined);
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/Cache/Fail"), 1, TR::DebugCounter::Undetermined);
srm->reclaimScratchRegister(castClassCacheReg);
}

// superclass test
if((NULL == toClassSymRef) || !toClassSymRef->isClassInterface(comp))
{
const int32_t flags = (J9AccInterface | J9AccClassArray);
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/SuperclassTest", comp->signature()), 1, TR::DebugCounter::Undetermined);
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/SuperclassTest"), 1, TR::DebugCounter::Undetermined);
if (toClassDepth == -1)
{
genTestModifierFlags(cg, node, toClassReg, toClassDepth, helperCallLabel, srm, flags);
if (feGetEnv("enableInlineItableWalkForIsAssignableFrom")) {
TR::Register *modifierReg = srm->findOrCreateScratchRegister();
generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, modifierReg,
generateS390MemoryReference(toClassReg, offsetof(J9Class, classDepthAndFlags), cg));
genTestModifierFlags(cg, node, toClassReg, toClassDepth, ITableTestLabel, srm, J9AccInterface, modifierReg);
genTestModifierFlags(cg, node, toClassReg, toClassDepth, helperCallLabel, srm, J9AccClassArray, modifierReg);
srm->reclaimScratchRegister(modifierReg);
} else {
genTestModifierFlags(cg, node, toClassReg, toClassDepth, helperCallLabel, srm, J9AccInterface | J9AccClassArray);
}
}
genSuperclassTest(cg, node, toClassReg, toClassDepth, fromClassReg, failLabel, srm);
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BE, node, successLabel);
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/SuperclassTest/Fail", comp->signature()), 1, TR::DebugCounter::Undetermined);
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/SuperclassTest/Fail"), 1, TR::DebugCounter::Undetermined);
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, helperCallLabel);
}
// we don't generate ITable test if we know we don't have an interface
if ((toClassDepth == -1) || (NULL == toClassSymRef || toClassSymRef->isClassInterface(comp)))
{
generateS390LabelInstruction(cg, TR::InstOpCode::label, node, ITableTestLabel);
// no need for helper if we fail interface test - we known the cast class is an interface
genITableTest(node, cg, srm, fromClassReg, toClassReg, doneLabel, failLabel);
}
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, helperCallLabel);
}

srm->stopUsingRegisters();
Expand Down