Jikes RVM doesn't update TIBs of array classes for recompiled java.lang.Object methods


When Jikes RVM recompiles a method, it tries to update the compiled method in all TIBs that point to that method. However, if Jikes RVM recompiles a java.lang.Object method such as hashCode() or clone() or wait(), it doesn't update the TIBs for all array types (all array types inherently extend java.lang.Object) since they're not known.

In unmodified Jikes RVM, this is mainly a performance issue. However, for any project that's adding instrumentation or making other behavior changes, it could be functionally important that the recompiled method gets called instead of the old compiled method.

I believe the issue is not all that difficult to fix: just iterate over all array types and replace the method. There are only a handful of java.lang.Object methods, so this will only happen a few times in an execution (unless the same methods are recompiled over and over again), and it'll never happen in a FastAdaptive run since java.lang.Object methods won't get recompiled by default during an execution.

Here's my fix:

RVMClass.updateMethod() should have some code added at the end:

public void updateMethod(RVMMethod m) {
if (VM.VerifyAssertions) VM._assert(isResolved());
if (VM.VerifyAssertions) VM._assert(m.getDeclaringClass() == this);
if (m.isClassInitializer()) return; // we never put this method in the jtoc anyways!

if (m.isStatic() || m.isObjectInitializer()) {
} else {
// Here's the new code:
// If this is a java.lang.Object method, also update all the TIBs for array types (since arrays can call this method)
if (m.getDeclaringClass().isJavaLangObjectType()) {
// Start at slot 1 since slot 0 is null (see BootImageWriter and BootImageWriterConstants)
for (int i = 1; i < RVMType.numTypes(); i++) {
RVMType type = RVMType.getType;
if (type.isArrayType()) {
if (type.isResolved()) {
TIB tib = type.getTypeInformationBlock();
tib.setVirtualMethod(m.getOffset(), RVMType.JavaLangObjectType.getTypeInformationBlock().getVirtualMethod(m.getOffset()));

Admittedly, that's a bit clunky. For example, RVMType.numTypes() says it's only intended to be used by the boot image writer. It would be better to put the code starting at the for-loop in a static synchronized method in RVMType, so that RVMType.nextId is properly synchronized.

After this fix, CompiledMethods.setCompiledMethodObsolete() can be simplified to the following:

public static void setCompiledMethodObsolete(CompiledMethod compiledMethod) {
scanForObsoleteMethods = true;

This helps an implementation that needs to recompile every method with different instrumentation in the middle of a run. I haven't tested it more thoroughly than that.

Acknowledgment: Thanks to my research group (http://www.cse.ohio-state.edu/~mikebond/plass) for helpful discussions and feedback.




Erik Brangs


Michael Bond




Fix versions

Affects versions