Java Forum / Virtual Machine / March 2007
Adding constructor by bytecode instrumentation
Moritz Hammer - 20 Mar 2007 11:31 GMT Hello,
I am trying to use JVMTI to instrument the bytecode of all classes up to java.lang.Object. I need this so I can have a plain constructor (with some special signature) that does not do anything besides calling a superclass constructor that also does nothing (I want to simulate the effect of the actual constructor later). Right now, that does not sound too complicated to me: add another <init> method in the constant pool and a method block later. However, before I start, I wanted to ask people who know whether it can really be done: adding another constructor to java.lang.Object (or, at least, any direct subclass). Any pitfalls I am currently heading to? Is there any framework I can use (I do not want to permanently instrument all Java classes, so unless I am mistaken, I need to do it with JVMTI and implement it in C to get a grasp on java.lang.Object).
Any hints are greatly appreciated, Moritz
Chris Uppal - 20 Mar 2007 23:59 GMT > However, before I start, I wanted to ask people who > know whether it can really be done: adding another constructor to > java.lang.Object (or, at least, any direct subclass). Yes it can be done. I've just tried it with JDK 1.6.0 and it seems to work fine.
-- chris
Moritz Hammer - 23 Mar 2007 11:18 GMT > Yes it can be done. I've just tried it with JDK 1.6.0 and it seems to work > fine. Just for the record: Indeed it works, and it only takes some minor modification to the java_crw_demo sources supplied with JDK 1.6 (persumably with 1.5 also) to get things working. There is a minor issue with obtaining a unique constructor signature, which I first attempted to get with a unique class reference; but this leads to problems, since the class loader cannot load the class it has been instrumented with... I would have to add that class to the bootstrap class loader, but then I just went with a very obscure combination of primitive types as the signature; it will be fun to see when I get clashes with existing constructors ;-)
Thank you for your reply, Moritz
Chris Uppal - 26 Mar 2007 11:36 GMT > There is a minor issue with > obtaining a unique constructor signature, which I first attempted to get > with a unique class reference; but this leads to problems, since the class > loader cannot load the class it has been instrumented with... I used [D[D[D as the signature in my test. Now I come to think about it, I can't see why the double[] array doesn't suffer from the same problem (double[] is a subclass of Object after all). But, since it doesn't (at least with a Sun 1.6 JVM), a neat way of getting a unique signature is to use something like not.defined.Anywhere[] as the parameter type (pass a null if you want to invoke it, of course).
-- chris
Moritz Hammer - 26 Mar 2007 13:24 GMT > I used [D[D[D as the signature in my test. Now I come to think about > it, I can't see why the double[] array doesn't suffer from the same [quoted text clipped - 3 lines] > not.defined.Anywhere[] > as the parameter type (pass a null if you want to invoke it, of course). Well, I am not entirely sure, but I think it is a bootstrap class loading issue. java.lang.Object gets loaded anyway, but not.defined.Anywhere requires a genuine ClassLoader to be loaded, unless put into the bootstrap classpath. I just checked, if you put it in the bootstrap classpath, things are working ok. Maybe a cleaner solution than using an "unlikely" signature - I used "DIFFZIFF" ;-) If not.defined.Anywhere is not put into the bootstrap classpath, the instrumented ClassLoader subclass gets screwed, since it requires a loaded instance of not.defined.Anywhere to get started, and this leads to very strange errors.
Regards, Moritz
Chris Uppal - 27 Mar 2007 06:30 GMT > Maybe a cleaner solution than using an "unlikely" > signature - I used "DIFFZIFF" ;-) If not.defined.Anywhere is not put into > the bootstrap classpath, the instrumented ClassLoader subclass gets > screwed, since it requires a loaded instance of not.defined.Anywhere to > get started, and this leads to very strange errors. I'm probably misunderstanding you, but I don't see why you'd have to load class not.defined.Anywhere at all -- there's no need to create an instance just to call a method with that signature. I was able to call my additional Object constuctor with bytecode:
new java/lang/Object aconst_null invokespecial java/lang/Object/<init> ([Lnot/defined/Anywhere;)V
Which worked, in that my constuctor was called, but of course I had nothing comparable to your custom classloader in my test settup.
-- chris
Moritz Hammer - 27 Mar 2007 09:58 GMT > I'm probably misunderstanding you, but I don't see why you'd have to load class > not.defined.Anywhere at all -- there's no need to create an instance just to [quoted text clipped - 7 lines] > Which worked, in that my constuctor was called, but of course I had nothing > comparable to your custom classloader in my test settup. I instrument every class with the additional constructor, and if not.defined.Anywhere is not in the bootclasspath, I get the exception:
Error occurred during initialization of VM java.lang.NullPointerException at java.util.Hashtable.put(Hashtable.java:394) at java.lang.System.initProperties(Native Method) at java.lang.System.initializeSystemClass(System.java:1072)
This is independent on whether not.defined.Anywhere is in the classpath or not. I excluded various classes from instrumentation, and eventually found that if I exclude the ClassLoader subclasses and some classes from sun.* packages (apparently related to reading the actual bytecode), thinks work ok. Therefore I suspect that the ClassLoader cannot be instrumented.
If I instrument java.lang.Object only, things are ok even if not.defined.Anywhere is indeed not defined anywhere. But then I get a ClassNotFoundException when I use reflection to see the constructors. I have not tried assembling the bytecode to invoke the special java.lang.Object constructor. That might work.
I assume you are right, and not.defined.Anywhere needs not be loaded if it is used for the signature of a constructor invoked directly. If reflection is used to get the constructor, and I guess this is the case with the ClassLoader subclasses, then not.defined.Anywhere needs to be loaded.
Regards, Moritz
Cyril Shelest - 29 Mar 2007 21:23 GMT Hi, I did the same you mentioned. In my product that written with pure C++ I developed a code that parses Java bytecode, decomposes it into a syntax tree. The syntax tree is modified to add new methods/constructors. And then from this syntax tree I generate a new Java bytecode. The products that include this algorithm are avalable at http://www.simtel.net/product.php[id]94368[SiteID]simtel.net and http://www.simtel.net/product.php[id]93174[SiteID]simtel.net
> Hello, > [quoted text clipped - 14 lines] > Any hints are greatly appreciated, > Moritz
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|