[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[aspectj-dev] RE: [aspectj-users] Using the -injar compiler option

> James Howe wrote:
> > 2. Ran the ajc compiler as follows:
> >
> >    ajc -injars rt.jar -aspectpath unitTestAspects.jar -outjar rt_aj.jar
> >
> > After fixing an OutOfMemory error by increasing the memory available to
> > ajc, I ran the compiler once again.  After a period of time the compiler
> > aborted with the following:
> >
> > java.lang.StackOverflowError
> >         at
> org.aspectj.weaver.bcel.Utility.getSourceLine(Utility.java:436)
> >         at
> org.aspectj.weaver.bcel.Utility.getSourceLine(Utility.java:436)
> >         ...
> >
> > I'm running with AspectJ 1.1rc2 on Windows XP with JDK 1.4.01.

This bug was so much fun to fix that I wanted to share the solution with both users and dev.  Wes Isberg noted the most likely source of the problem:

Wes Isberg wrote:
> Hmm... looks like a cycle in the InstructionHandle list:
> 
> ---- Utility.java
>   public static int getSourceLine(InstructionHandle ih) {
>     if (ih == null) return -1;
>     <snip...>
>     return getSourceLine(ih.getNext()); // StackOverflow here
>  }

This was also my first guess.  The only problem with this analysis is that the bug disappears when running the compiler under JDK 1.3.1.  How could changing the JVM used for running the compiler possibly affect this behavior?

Well, a StackOverflowError doesn't actually mean that you have an infinite loop in your program.  All good computer scientists know that detecting infinite loops is impossible.  All a StackOverflowError means is that some arbitrary limit on stack size has been exceeded.  It turns out that the default limit in SUN's 1.4 JVM is smaller than the default limit in SUN's 1.3 JVM.

This getSourceLine method was being called for a very large method which didn't contain any SourceLine information.  So, getSourceLine was called recursively many times and before it reached the end of the method's instructions it ran out of stack (but only on the smaller stack in 1.4).

The astute reader will notice that the getSourceLine method is something called "tail-recursive" which means that a clever JVM doesn't have to keep around any stack information when making the recursive call.  I've listened to many theoretical discussions about how horrible it is that the JVM doesn't implement tail-recursion "properly", but this was the first time that I've actually been bit by this as a bug.  For more on tail recursion try http://www.google.com/search?q=tail+recursion.  (BTW - Given that this is the first time I've been bitten by this problem in 6 years of Java programming I'm still not very sympathetic to those who believe "proper" tail recursion is a VM's sine qua non.)

Anyway, the fix was just to replace the recursive call with the obvious "while (ih != null)" loop instead.  This makes the JVM happier and doesn't make the method any harder to understand.  The only hard part about this bug was isolating it from the seemingly arbitrary environmental factors that could make it appear and disappear.

I hope this was interesting to someone - Jim