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
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
invokestatic, it seems, do require the actual class.
I’m looking at the definition of
invokespecial 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
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.
invokestatic instruction does not use any kind of special lookup. Any
invokestatic calls to
Object methods will have to be rewritten.