- A Concurrent Affair - https://www.concurrentaffair.org -

Just Changing Superclass Not Enough

One of the last things I’d written and begun to test before the accident was an instrumentor called ProperObjectSuperClassStrategy. It changes all classes that extend Object to extend my own ProperObject. However, this is currently only done on a class level. When I briefly tested it, of course it didn’t work.

The methods in Java are handled individually. So what this strategy also has to do is change all method calls that have Object as target to calls to ProperObject.

Update

That isn’t true. Virtual calls happen without knowing the exact target class, of course. But static and constructor calls, i.e. calls made by invokespecial and invokestatic, it seems, do require the actual class.

Update

I’m looking at the definition of invokespecial [1] right now:

Next, the resolved method is selected for invocation unless all of the following conditions are true:

  • The ACC_SUPER flag is set for the current class.
  • The class of the resolved method is a superclass of the current class.
  • The resolved method is not an instance initialization method.

If the above conditions are true, the actual method to be invoked is selected by the following lookup procedure. Let C be the direct superclass of the current class:

  • If C contains a declaration for an instance method with the same name and descriptor as the resolved method, then this method will be invoked. The lookup procedure terminates.
  • Otherwise, if C has a superclass, this same lookup procedure is performed recursively using the direct superclass of C. The method to be invoked is the result of the recursive invocation of this lookup procedure.
  • Otherwise, an AbstractMethodError is raised.

If I read this right, it means that instance initialization methods (<init>) will always be called directly, without any further lookup, as will methods outside the current classes hierarchy. If a method in the current hierarchy is called that is not an instance initializer, then the class hierarchy is traversed up until a method has been found.

For the latter case, nothing has to be done. Object is still the end of the chain, but ProperObject‘s methods will be found first. For instance initializers and calls to outside this hieararchy, I will have to perform the changes, i.e. if a call to Object.<init> is being made, it has to be changed to ProperObject.<init>. For Object, the case of “calls to outside the hierarchy” doesn’t really apply, because everything is a subclass of Object, but it is worth keeping in mind that if I ever do this for other classes, I will have to perform the same change for these calls too.

The invokestatic [1] instruction does not use any kind of special lookup. Any invokestatic calls to Object methods will have to be rewritten.

[2] [3]Share [4]