-
Notifications
You must be signed in to change notification settings - Fork 740
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor SuperclassTest generators on Z #20906
Refactor SuperclassTest generators on Z #20906
Conversation
f845b5b
to
b5b2cd2
Compare
@r30shah please review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Matthew, I was under impression that genInstanceOfOrCheckcastSuperClassTest
can be refactored/updated to something like genSuperClassTest
which handles the cases for all three - instanceOf/ CHeckCast / isAssignableFrom to ensure that if there are any changes that happens in the future to class structure, we can make sure that only one place is changed and we do not need to go through all three places where super class test is generated to mae sure.
Please share the reason behind this (As you are using assignableFrom, may be some code that makes it difficult to use the single SuperClassTest function). so would like to know.
That being said, if we are going down the path of having SuperClassTest changed into three function, we should write a good comment explaining what it is doing, and also have properName to the helper function (May be testClassFlagsForSuperClassTest, testClassDepthForSuperClassTest).
/** | ||
* generates code to branch to <callHelperLabel> if any of the J9ROMClass modifier flags match the given flags <flags> | ||
*/ | ||
static void genTestRuntimeFlags(TR::CodeGenerator *cg, TR::Node *node, TR::Register *classReg, int32_t toClassDepth, TR::LabelSymbol *callHelperLabel, TR_S390ScratchRegisterManager *srm, int32_t flags, const char *callerName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I wonder how are you using this function. The runtime check for interface or abstract class is used when the other tests in the checkcast / instance of fails and it is a safeguard to do so before loading the class from super class array. I would think of this test is always coming with super class test. That being said, can you share the logic behind this ?
Also genTestRuntimeFlags
is not very suitable name for what it is doing (Rather misleading actually) as it is doing test to ensure that it is not interface / array before doing super class test.
* Loads the class depth of the toClass (if needed) as well as the depth of the fromClass. | ||
* Genereates code to compare the 2 depths and branch to the failLabel if fromClassDepth <= toClassDepth | ||
*/ | ||
static TR::Register *genLoadAndCompareClassDepth(TR::CodeGenerator *cg, TR::Node *node, TR::Register *toClassReg, int32_t toClassDepth, TR::Register *fromClassReg, TR::LabelSymbol *failLabel, TR_S390ScratchRegisterManager *srm, const char *callerName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above. Everything that it is doing is specific to Super Class test where some of the core-login behind class depth and array/interface should be the same. So would appreciate if you can share the reason behing this.
@r30shah This change does handle all 3 cases. Did I miss a spot where Regarding #20906 (comment), For example, if we still want the CHelper call for Array Classes for isAssignableFrom, but want to inline the test for interfaces, we can do something like
But if we want to keep CheckCast the way it is right now, we just use
Additionally, the runtime check for an Interface or Array Class is not just a safeguard. Only To sum it up the overall idea was to allow for greater expandability. For #20906 (comment), similar to above, the idea behind separating it was so it could be used if we decide to inline all or part of the superclass test for Array Classes. This would allow us to do a similar class-depth-check shortcut. |
Thanks a lot @matthewhall2 for the explanation. Do we have a potential test that we would be doing when doing the if it is interface or not. Existing code for
That is incorrect. Code that prepares the list of test to be generated at compile time for instance Of and checkCast [1] does that. It would be very inefficient if we do not check the information which is available at compile time and go all out with test to be performed at runtime. If we know that the cast class is not regular class at compile time, why do we even do super class test ? Only case where we would actually check class is interface or array class at runtime is when we have a dynamic cast class (Which will be result of when cast class is not compile time constant - which I think you can generate this test with [1].
|
Thank you for the clarification @r30shah . For abstract class, I want to add the skip over the class equality test and add the existing I was also planning on looking into the same tests we already have but for Array Classes. For example, the inline superclass test it not generated for any of instanceof, checkcast, isassignableFrom for Array Classes. |
Are these tests you are talking about, you are planning to add for Class.isAssignableFrom ? or checkCast / instanceOf (The iTable walk routine was already something I think we should implement and thing about reducing the inline code we are generated) But that IMO is beyond the scope of improving the Class.isAssignableFrom from the current implementation. If this approach is allowing you to make progress, I am OK with you separating the Super Class test generation to different helper function if that makes sense to you with the current implementation state. But I would factor in the places where we may need to change - Currently, it is only the genSuperClassTest that is needed to be changed and also you more relatable names for the function. |
b5b2cd2
to
a74f843
Compare
@r30shah can you review again please? Tests for java8 are passing on a development branch. Tests for this branch are currently running (no difference between this branch and the dev branch, just did not want to push a bunch of changes while I figured out the issue). Considering how often I'll fix the line endings when the jenkins tests finish to avoid having to restart the tests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have done half review (Atleast the code used in check-cast) some of the comments would be same, so please apply general changes to both evaluators, Will do complete review when you address the comments.
* through helper call if result of SuperClassTest turned out to be false. | ||
*/ | ||
|
||
int32_t flags = J9AccInterface | J9AccClassArray; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple of things, as J9AccInterface
/ J9AccInterface
is constant, we should use constant here. Also why do we need to pass the flag to the genTestModifierFlags
- Is it because that will be different for checkCast/InstantOf/CheckAssignableFrom ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the checks are different for isAssignableFrom (we also check for Abstract there).
Also, since we are likely to be adding inlined tests for the case where castClass is an interface, the flags passed in will change in the future (genTestModifierFlags will be called multiple times. I have changed the design of genTestModifierFlags to accommodate this more efficiently. Now it skips the load when we already have the flags)
*/ | ||
|
||
int32_t flags = J9AccInterface | J9AccClassArray; | ||
genTestModifierFlags(cg, node, castClassReg, castClassDepth, callLabel, srm, flags, "checkcast"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the purpose of passing the checkcast
(callerName) constant string here ? If there is an assert that is being thrown in the function - that assert should be followed by the stack trace, so we would know where that is coming from, apart from that if you are using this in trace message, in the trace log you would know which node you are generating instruction for.
@@ -4573,6 +4540,8 @@ J9::Z::TreeEvaluator::checkcastEvaluator(TR::Node * node, TR::CodeGenerator * cg | |||
if (comp->getOption(TR_TraceCG)) | |||
traceMsg(comp, "%s: Emitting Profiled Class Test\n", node->getOpCode().getName()); | |||
TR::Register *arbitraryClassReg1 = srm->findOrCreateScratchRegister(); | |||
if (comp->getOption(TR_TraceCG)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this was the temp. change for the issue you are debugging - May not need this - we can see what instruction we generated to know how that instruction was used.
@@ -4592,6 +4561,8 @@ J9::Z::TreeEvaluator::checkcastEvaluator(TR::Node * node, TR::CodeGenerator * cg | |||
traceMsg(comp, "%s: Emitting Compile Time Guess Class Test\n", node->getOpCode().getName()); | |||
cg->generateDebugCounter(TR::DebugCounter::debugCounterName(comp, "checkCastStats/(%s)/CompTimeGuess", comp->signature()),1,TR::DebugCounter::Undetermined); | |||
TR::Register *arbitraryClassReg2 = srm->findOrCreateScratchRegister(); | |||
if (comp->getOption(TR_TraceCG)) | |||
traceMsg(comp, "Scratch reg for compile time guess test: %s\n", arbitraryClassReg2->getRegisterName(comp)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as before.
@@ -4619,6 +4590,8 @@ J9::Z::TreeEvaluator::checkcastEvaluator(TR::Node * node, TR::CodeGenerator * cg | |||
if (comp->getOption(TR_TraceCG)) | |||
traceMsg(comp,"%s: Emitting CastClassCacheTest\n",node->getOpCode().getName()); | |||
TR::Register *castClassCacheReg = srm->findOrCreateScratchRegister(); | |||
if (comp->getOption(TR_TraceCG)) | |||
traceMsg(comp, "Scratch reg for cast class cache test: %s\n", castClassCacheReg->getRegisterName(comp)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as before - If you want to increase readability of the code generated code - may be add instruction comment
@@ -4492,12 +4445,22 @@ J9::Z::TreeEvaluator::checkcastEvaluator(TR::Node * node, TR::CodeGenerator * cg | |||
if (comp->getOption(TR_TraceCG)) | |||
traceMsg(comp, "%s: Class Not Evaluated. Evaluating it\n", node->getOpCode().getName()); | |||
castClassReg = cg->evaluate(castClassNode); | |||
if (comp->getOption(TR_TraceCG)) | |||
traceMsg(comp, "cast class is in reg: %s\n", castClassReg->getRegisterName(comp)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as in other places.
break; | ||
case LoadObjectClass: | ||
if (comp->getOption(TR_TraceCG)) | ||
traceMsg(comp, "%s: Loading Object Class\n",node->getOpCode().getName()); | ||
objClassReg = cg->allocateRegister(); | ||
if (comp->getOption(TR_TraceCG)) | ||
traceMsg(comp, "obj class is in reg: %s\n", objClassReg->getRegisterName(comp)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as in other places.
int32_t castClassDepth = castClassNode->getSymbolReference()->classDepth(comp); | ||
if (castClassDepth == -1) | ||
{ | ||
cg->generateDebugCounter("matthew/checkcast/depth_unknown", 1, TR::DebugCounter::Undetermined); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you generate a dynamic debug counter for info that is known at compile time. Also - please refrain naming your debug counter like you have here - keep it more standard. Think about asking some customer to get information using debug counter and asking them to use the string you have used here ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, sorry, all the counters with "matthew/" were for debugging or to count number of invocations on interface vs abstract vs ... . I have removed them
} | ||
else | ||
{ | ||
cg->generateDebugCounter("matthew/checkcast/depth_known", 1, TR::DebugCounter::Undetermined); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above
b582627
to
1847f0e
Compare
f04dc58
to
d64e97a
Compare
please review again @r30shah . Adding ICF labels to |
{ | ||
memmove(&sequences[j + 2], &sequences[j], (i - j) * sizeof(InstanceOfOrCheckCastSequences)); | ||
sequences[j] = LoadObjectClass; | ||
sequences[j + 1] = StartICF; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although, I am OK with this approach as well - Now as we know the reason behind you getting those Assert message about assigning register within ICF, can we actually start the ICF region in the beginning on the evaluator (Probably after object is evaluated) conservatively ? Would that cause any issue ?
Also, if we are going this way (If conservatively putting ICF works then I would prefer that option) this function is being used by P and ARM code gen as well and we need to make sure their evaluator does not run into this functional issue or hit any assert with this test added. Either changes need to be made there or guard this by Z changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, that should not cause any issue. I'll make the change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, that should not cause any issue. I'll make the change
Making change in other codegen or here ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Taking out this change and adding the ICF label conservatively in the Z evaluators
// convert this offset to a real J9Class pointer | ||
#endif | ||
if (dynamicCastClass) | ||
TR_ASSERT(flags < UINT_MAX && flags > 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now as you are passing a flag, the assert comment and the check does not match. I think this assert should make more sense in the evaluator calling this.
TR::Register *scratchReg = modiferReg == NULL ? srm->findOrCreateScratchRegister() : modiferReg; | ||
TR::Instruction *cursor = NULL; | ||
TR_Debug * debugObj = cg->getDebug(); | ||
if (!modiferReg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain the purpose behind this register being passed ? I would assume this is something you are planning to pass from Class.isAssignableFrom - Please use the name that explains the purpose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The register is generated by this function, and returned when keepScratchReg
is true.
The purpose is so that is can be passed back in when the function is called again to avoid having to load the flags from memory again
// For dynamic cast class genInstanceOfOrCheckcastSuperClassTest will generate branch to either helper call or dynamicCacheTest depending on the next generated test. | ||
dynamicCastClass = genInstanceOfOrCheckcastSuperClassTest(node, cg, objClassReg, castClassReg, castClassDepth, falseLabel, *(iter+1) == DynamicCacheDynamicCastClassTest ? dynamicCacheTestLabel : callLabel, srm); | ||
|
||
dynamicCastClass = castClassDepth == -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dynamicCastClass = castClassDepth == -1; | |
dynamicCastClass = ( castClassDepth == -1 ); |
@@ -11643,17 +11552,15 @@ static bool inlineIsAssignableFrom(TR::Node *node, TR::CodeGenerator *cg) | |||
cg->decReferenceCount(node->getFirstChild()); | |||
cg->decReferenceCount(node->getSecondChild()); | |||
|
|||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary extra line.
TR::LabelSymbol *callHelperLabel = *(iter+1) == DynamicCacheDynamicCastClassTest ? dynamicCacheTestLabel : callLabel; | ||
genTestModifierFlags(cg, node, castClassReg, castClassDepth, callHelperLabel, srm, flags); | ||
genSuperclassTest(cg, node, castClassReg, castClassDepth, objClassReg, falseLabel, srm); | ||
dynamicCastClass = castClassDepth == -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Already computed. Remove this line.
* through helper call if result of SuperClassTest turned out to be false. | ||
*/ | ||
|
||
const int32_t flags = J9AccInterface | J9AccClassArray; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const int32_t flags = J9AccInterface | J9AccClassArray; | |
const int32_t flags = ( J9AccInterface | J9AccClassArray ) ; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you missed this one.
else if (outOfBound) | ||
fromClassDepthReg = srm->findOrCreateScratchRegister(); | ||
cursor = generateRXInstruction(cg, loadOp, node, fromClassDepthReg, | ||
generateS390MemoryReference(fromClassReg, offsetof(J9Class, classDepthAndFlags) + bytesOffset, cg)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
insert tabs to move this line indented after cg.
{ | ||
toClassDepthReg = srm->findOrCreateScratchRegister(); | ||
cursor = generateRXInstruction(cg, loadOp, node, toClassDepthReg, | ||
generateS390MemoryReference(toClassReg, offsetof(J9Class, classDepthAndFlags) + bytesOffset, cg)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as peviously with indentation.
d64e97a
to
f89af39
Compare
3c89953
to
6ecc0a0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apart from the slight design change of your implementation of genTestModifierFlags
, some minor nitpicks. Overall changes looks ok to me. Once you make the change, please launch the sanity tests internally and share the link of the builds with me on slack
. I will also on parallel launch tests here.
bool eliminateSuperClassArraySizeCheck = (!dynamicCastClass && (castClassDepth < comp->getOptions()->_minimumSuperclassArraySize)); | ||
|
||
// don't want to waste a load and/or AND if we can check the flags at compile time | ||
if (classDepth != -1) return NULL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a point of calling this function when cast class is not known at compile time. I think caller should ensure that this function is not called for known compile time known class and we should have Fatal assert here,
) | ||
/** Used in conjunction with genSuperclassTest as part of the Superclass test for checkcast, instanceof, Class.isAssignableFrom | ||
* Generates branch instruction to jump to <handleFlagsLabel> when at least one of the modifiers of the class in <classReg> matches the given flags | ||
* If modifier reg is non-null, no load instruction will be generated, and modiferReg if assumed to contain the J9ROMClass modifiers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would have preferred the caller to allocate the register (either through SRM or itself) and pass it here if it wants to use the loaded modifiers off the classReg and skip it here, as that way caller have control on the registers being used in the evaluator and if the caller does not pass the register, the function would get a scratch register and reclaim it at the end, fits in with the design of the SRM - and you do not end up in scenario where someone mistakenly call this function with j9classModifierFlagsReg
and keepScratchReg
set to false - which later is reclaimed in this function - which may not something someone want.
|
||
cursor = generateRILInstruction(cg, TR::InstOpCode::NILF, node, scratch1Reg, static_cast<int32_t>((J9AccInterface | J9AccClassArray)), cursor); | ||
cursor = generateRXInstruction(cg, TR::InstOpCode::L, node, scratchReg, | ||
generateS390MemoryReference(scratchReg, offsetof(J9ROMClass, modifiers), cg)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same suggestion as above.
|
||
if (!keepScratchReg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I mentioned, I do find it error prune for someone to incorrectly use this function. It should be simple, if the caller wants to keep the register, it should allocate one and load the value itself, rather than having this back and forth.
{ | ||
toClassDepthReg = srm->findOrCreateScratchRegister(); | ||
cursor = generateRXInstruction(cg, loadOp, node, toClassDepthReg, | ||
generateS390MemoryReference(toClassReg, offsetof(J9Class, classDepthAndFlags) + bytesOffset, cg)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as peviously with indentation.
cursor = generateRXInstruction(cg, loadOp, node, toClassDepthReg, | ||
generateS390MemoryReference(toClassReg, offsetof(J9Class, classDepthAndFlags) + bytesOffset, cg)); | ||
if (debugObj) | ||
debugObj->addInstructionComment(cursor, "Load castClass depth"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am ok with using toClass
and fromClass
from castClass
and objectClass
(Whch is the more common and understandable terminology with instanceof and checkcast and would have preferred that) respectively. In the comment keep this consistent.
@@ -4397,7 +4241,7 @@ J9::Z::TreeEvaluator::checkcastEvaluator(TR::Node * node, TR::CodeGenerator * cg | |||
TR::Register *castClassCopyReg = NULL; | |||
TR::Register *resultReg = NULL; | |||
|
|||
// We need here at maximum two scratch registers so forcing scratchRegisterManager to create pool of two registers only. | |||
int32_t castClassDepth = castClassNode->getSymbolReference()->classDepth(comp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think use of this variable is only needed when we are generating SuperClassTest, please move it closer to the point it is being used. This will reduce the scope of live register in the compiled C code.
TR_ASSERT(flags < UINT_MAX && flags > 0, "superclass test::(J9AccInterface | J9AccClassArray) is not a 32-bit number\n"); | ||
|
||
// For dynamic cast class to next 2 calls will generate branch to either helper call or dynamicCacheTest depending on the next generated test. | ||
TR::LabelSymbol *callHelperLabel = *(iter+1) == DynamicCacheDynamicCastClassTest ? dynamicCacheTestLabel : callLabel; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TR::LabelSymbol *callHelperLabel = *(iter+1) == DynamicCacheDynamicCastClassTest ? dynamicCacheTestLabel : callLabel; | |
TR::LabelSymbol *callHelperLabel = (*(iter+1) == DynamicCacheDynamicCastClassTest) ? dynamicCacheTestLabel : callLabel; |
30a46e1
to
d0fb5ab
Compare
Commons out code in genTestIsSuper and genInstanceOfOrCheckCastSuperClassTest into 2 helpers (genTestModifierFlags, genSuperclassTest) Replaces calls to the old generators with calls to the 2 new methods. Adds ICF labels to checkcast and instanceof evaluators. Adds StartICF sequence to InstanceOfOrCheckCastSequences. Signed-off-by: Matthew Hall <[email protected]>
d0fb5ab
to
42b06f3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approving this, you may have missed one recommendation. Gonna let is pass by.
* through helper call if result of SuperClassTest turned out to be false. | ||
*/ | ||
|
||
const int32_t flags = J9AccInterface | J9AccClassArray; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you missed this one.
jenkins test sanity all jdk11,jdk21 |
failures are all on |
I agree, changes in this PR should not have any impact on other platform. I am relaunching sanity run with JDK21 before merging this today. |
jenkins test sanity zlinux jdk21 |
S390 failure in https://openj9-jenkins.osuosl.org/job/Test_openjdk21_j9_sanity.functional_s390x_linux_Personal/331 was related to #18048. |
Commons out code in
genTestIsSuper
andgenInstanceOfOrCheckCastSuperClassTest
into 3 helpers (genTestRuntimeFlags
,genLoadAndCompareClassDepth
,genCheckSuperclassArray
)Replaces calls to the old generators with calls to the 3 new