I’ve begun working on my alternative approach. If I can’t add fields to java.lang.Object
, I’ll just add them to all direct subclasses. Once this is done, all objects will have the fields since nothing is ever just an Object
.
First I scan through all files, and if they are subclassing java.lang.Object
, I add the field for the object ID. This ID has to be initialized once and only once, though, which has to happen in the constructors. This is complicated by the fact that one constructor may call another:
public class ThisCtorTest {
public ThisCtorTest() {
System.out.println("ThisCtorTest()");
}
public ThisCtorTest(int i) {
this();
System.out.println("ThisCtorTest("+i+")");
}
}
Here, a call to ThisCtorTest(int i)
will also invoke ThisCtorTest()
. If the initialization code is added to both constructors, it would be run twice.
Conceptually, the constructors (their name in the class files is <init>
) form a call graph:
I only add the initialization code to constructors that are sinks, that don’t call any other constructors. In this example, these constructors are <init>\_0
and <init>\_2
. Calls to <init>\_1
and <init>\_3
both invoke <init>\_0
and thus execute the initialization code.
If I decide to initialize the field, this code will be inserted:
aload\_0
getstatic (nextObjectID)
dup2
lconst\_1
ladd
putstatic (nextObjectID)
putfield (objectID)
which corresponds to the Java code
objectID = nextObjectID++;
I may have to make this section synchronized.
Of course, nothing is so simple with the JVM that it could work right away, now is it? :(