@@ -3378,7 +3378,7 @@ static void genTestModifierFlags(TR::CodeGenerator *cg, TR::Node *node, TR::Regi
3378
3378
TR::Instruction *cursor = NULL;
3379
3379
TR_Debug * debugObj = cg->getDebug();
3380
3380
3381
- if (! j9classModifierFlagsReg)
3381
+ if (NULL == j9classModifierFlagsReg)
3382
3382
{
3383
3383
generateRXInstruction(cg, TR::InstOpCode::getLoadOpCode(), node, scratchReg,
3384
3384
generateS390MemoryReference(classReg, offsetof(J9Class, romClass), cg));
@@ -3394,7 +3394,7 @@ static void genTestModifierFlags(TR::CodeGenerator *cg, TR::Node *node, TR::Regi
3394
3394
3395
3395
// when user passes in modiferFlags register, it is going to be reused later
3396
3396
// so we use an RRF instruction to avoid the flags being overwritten by the AND
3397
- if (j9classModifierFlagsReg)
3397
+ if (NULL != j9classModifierFlagsReg)
3398
3398
{
3399
3399
TR::Register *flagsReg = srm->findOrCreateScratchRegister();
3400
3400
generateRILInstruction(cg, TR::InstOpCode::IILF, node, flagsReg, flags);
@@ -3407,7 +3407,7 @@ static void genTestModifierFlags(TR::CodeGenerator *cg, TR::Node *node, TR::Regi
3407
3407
}
3408
3408
3409
3409
cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BNE, node, handleFlagsLabel);
3410
- if (! j9classModifierFlagsReg)
3410
+ if (NULL == j9classModifierFlagsReg)
3411
3411
srm->reclaimScratchRegister(scratchReg);
3412
3412
}
3413
3413
@@ -3484,23 +3484,28 @@ static void genSuperclassTest(TR::CodeGenerator *cg, TR::Node *node, TR::Registe
3484
3484
{
3485
3485
if (comp->target().is64Bit())
3486
3486
{
3487
- generateRSInstruction(cg, TR::InstOpCode::SLLG, node, toClassDepthReg, toClassDepthReg, 3);
3487
+ cursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, toClassDepthReg, toClassDepthReg, 3);
3488
3488
}
3489
3489
else
3490
3490
{
3491
- generateRSInstruction(cg, TR::InstOpCode::SLL, node, toClassDepthReg, 2);
3491
+ cursor = generateRSInstruction(cg, TR::InstOpCode::SLL, node, toClassDepthReg, 2);
3492
3492
}
3493
3493
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,
3495
3498
generateS390MemoryReference(superclassArrayReg, toClassDepthReg, 0, cg));
3496
3499
srm->reclaimScratchRegister(toClassDepthReg);
3497
3500
}
3498
3501
else
3499
3502
{
3500
3503
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,
3502
3505
generateS390MemoryReference(superclassArrayReg, superClassOffset, cg));
3503
3506
}
3507
+ if (debugObj)
3508
+ debugObj->addInstructionComment(cursor, "check superclass array");
3504
3509
srm->reclaimScratchRegister(superclassArrayReg);
3505
3510
}
3506
3511
@@ -11667,8 +11672,6 @@ J9::Z::TreeEvaluator::VMarrayCheckEvaluator(TR::Node *node, TR::CodeGenerator *c
11667
11672
return 0;
11668
11673
}
11669
11674
11670
- /////////////////////////////////////////////////////////////////////////////////
11671
- /////////////////////////////////////////////////////////////////////////////////
11672
11675
static bool inlineIsAssignableFrom(TR::Node *node, TR::CodeGenerator *cg)
11673
11676
{
11674
11677
static char *disable = feGetEnv("TR_disableInlineIsAssignableFrom");
@@ -11809,53 +11812,172 @@ static bool inlineIsAssignableFrom(TR::Node *node, TR::CodeGenerator *cg)
11809
11812
return true;
11810
11813
}
11811
11814
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
+
11812
11864
TR::Register *J9::Z::TreeEvaluator::inlineCheckAssignableFromEvaluator(TR::Node *node, TR::CodeGenerator *cg)
11813
11865
{
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);
11816
11872
11817
- TR::Register *resultReg = cg->allocateRegister();
11818
11873
TR::LabelSymbol *helperCallLabel = generateLabelSymbol(cg);
11819
11874
TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);
11820
- TR::LabelSymbol *successLabel = generateLabelSymbol(cg);
11821
-
11875
+ TR::LabelSymbol *failLabel = generateLabelSymbol(cg);
11876
+ TR::LabelSymbol *successLabel = doneLabel;
11822
11877
TR::LabelSymbol* cFlowRegionStart = generateLabelSymbol(cg);
11823
- generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);
11824
- cFlowRegionStart->setStartInternalControlFlow();
11825
11878
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);
11837
11880
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
11839
11882
TR_S390OutOfLineCodeSection *outlinedSlowPath = new (cg->trHeapMemory()) TR_S390OutOfLineCodeSection(helperCallLabel, doneLabel, cg);
11840
11883
cg->getS390OutOfLineCodeSectionList().push_front(outlinedSlowPath);
11841
11884
outlinedSlowPath->swapInstructionListsWithCompilation();
11842
-
11843
11885
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);
11846
11887
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, doneLabel); // exit OOL section
11847
11888
outlinedSlowPath->swapInstructionListsWithCompilation();
11848
11889
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
+ }
11851
11952
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);
11853
11976
deps->addPostCondition(fromClassReg, TR::RealRegister::AssignAny);
11854
11977
deps->addPostConditionIfNotAlreadyInserted(toClassReg, TR::RealRegister::AssignAny);
11855
- deps->addPostCondition(resultReg, TR::RealRegister::AssignAny);
11856
-
11857
11978
generateS390LabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps);
11858
11979
doneLabel->setEndInternalControlFlow();
11980
+
11859
11981
node->setRegister(resultReg);
11860
11982
return resultReg;
11861
11983
}
0 commit comments