@@ -11861,9 +11861,55 @@ 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();
11912+ cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromPath/(%s)", comp->signature()), 1, TR::DebugCounter::Undetermined);
1186711913 // recognizedCallTransformer swaps the args - caller class obj is the second argument after the transformation
1186811914 TR::Node *fromClass = node->getFirstChild();
1186911915 TR::Node *toClass = node->getSecondChild();
@@ -11875,6 +11921,7 @@ TR::Register *J9::Z::TreeEvaluator::inlineCheckAssignableFromEvaluator(TR::Node
1187511921 TR::LabelSymbol *failLabel = generateLabelSymbol(cg);
1187611922 TR::LabelSymbol *successLabel = doneLabel;
1187711923 TR::LabelSymbol* cFlowRegionStart = generateLabelSymbol(cg);
11924+ TR::LabelSymbol* ITableTestLabel = generateLabelSymbol(cg);
1187811925
1187911926 TR_S390ScratchRegisterManager *srm = cg->generateScratchRegisterManager(2);
1188011927
@@ -11897,11 +11944,11 @@ TR::Register *J9::Z::TreeEvaluator::inlineCheckAssignableFromEvaluator(TR::Node
1189711944 if (comp->getOption(TR_TraceCG))
1189811945 traceMsg(comp,"%s: Emitting Class Equality Test\n",node->getOpCode().getName());
1189911946 // 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);
11947+ cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/ClassEqualityTest"), 1, TR::DebugCounter::Undetermined);
1190111948 cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, toClassReg, fromClassReg, TR::InstOpCode::COND_BE, successLabel, false, false);
1190211949 if (debugObj)
1190311950 debugObj->addInstructionComment(cursor, "class equality test");
11904- cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/ ClassEqualityTest/Fail", comp->signature() ), 1, TR::DebugCounter::Undetermined);
11951+ cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/ClassEqualityTest/Fail"), 1, TR::DebugCounter::Undetermined);
1190511952
1190611953 int32_t toClassDepth = -1;
1190711954 TR::SymbolReference *toClassSymRef = getClassSymRefAndDepth(toClass, comp, toClassDepth);
@@ -11940,30 +11987,45 @@ TR::Register *J9::Z::TreeEvaluator::inlineCheckAssignableFromEvaluator(TR::Node
1194011987 if (comp->getOption(TR_TraceCG))
1194111988 traceMsg(comp,"%s: Emitting CastClassCacheTest\n",node->getOpCode().getName());
1194211989 TR::Register *castClassCacheReg = srm->findOrCreateScratchRegister();
11943- cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/ Cache", comp->signature() ), 1, TR::DebugCounter::Undetermined);
11990+ cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/Cache"), 1, TR::DebugCounter::Undetermined);
1194411991 generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, castClassCacheReg,
1194511992 generateS390MemoryReference(fromClassReg, offsetof(J9Class, castClassCache), cg));
1194611993 cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::getCmpRegOpCode(), node, castClassCacheReg, toClassReg, TR::InstOpCode::COND_BE, successLabel, false, false);
1194711994 if (debugObj)
1194811995 debugObj->addInstructionComment(cursor, "castclass cache test");
11949- cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/ Cache/Fail", comp->signature() ), 1, TR::DebugCounter::Undetermined);
11996+ cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/Cache/Fail"), 1, TR::DebugCounter::Undetermined);
1195011997 srm->reclaimScratchRegister(castClassCacheReg);
1195111998 }
1195211999
1195312000 // superclass test
1195412001 if((NULL == toClassSymRef) || !toClassSymRef->isClassInterface(comp))
1195512002 {
11956- const int32_t flags = (J9AccInterface | J9AccClassArray);
11957- cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/(%s)/SuperclassTest", comp->signature()), 1, TR::DebugCounter::Undetermined);
12003+ cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/SuperclassTest"), 1, TR::DebugCounter::Undetermined);
1195812004 if (toClassDepth == -1)
1195912005 {
11960- genTestModifierFlags(cg, node, toClassReg, toClassDepth, helperCallLabel, srm, flags);
12006+ if (feGetEnv("enableInlineItableWalkForIsAssignableFrom")) {
12007+ TR::Register *modifierReg = srm->findOrCreateScratchRegister();
12008+ generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, modifierReg,
12009+ generateS390MemoryReference(toClassReg, offsetof(J9Class, classDepthAndFlags), cg));
12010+ genTestModifierFlags(cg, node, toClassReg, toClassDepth, ITableTestLabel, srm, J9AccInterface, modifierReg);
12011+ genTestModifierFlags(cg, node, toClassReg, toClassDepth, helperCallLabel, srm, J9AccClassArray, modifierReg);
12012+ srm->reclaimScratchRegister(modifierReg);
12013+ } else {
12014+ genTestModifierFlags(cg, node, toClassReg, toClassDepth, helperCallLabel, srm, J9AccInterface | J9AccClassArray);
12015+ }
1196112016 }
1196212017 genSuperclassTest(cg, node, toClassReg, toClassDepth, fromClassReg, failLabel, srm);
1196312018 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);
12019+ cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "isAssignableFromStats/SuperclassTest/Fail"), 1, TR::DebugCounter::Undetermined);
12020+ generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, helperCallLabel);
12021+ }
12022+ // we don't generate ITable test if we know we don't have an interface
12023+ if ((toClassDepth == -1) || (NULL == toClassSymRef || toClassSymRef->isClassInterface(comp)))
12024+ {
12025+ generateS390LabelInstruction(cg, TR::InstOpCode::label, node, ITableTestLabel);
12026+ // no need for helper if we fail interface test - we known the cast class is an interface
12027+ genITableTest(node, cg, srm, fromClassReg, toClassReg, doneLabel, failLabel);
1196512028 }
11966- generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, helperCallLabel);
1196712029 }
1196812030
1196912031 srm->stopUsingRegisters();
0 commit comments