@@ -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+
1186411909TR::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