Bug 101290 - Compiler generates incorrect code
Summary: Compiler generates incorrect code
Status: RESOLVED DUPLICATE of bug 106130
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.2.1   Edit
Hardware: PC Windows XP
: P2 normal (vote)
Target Milestone: 1.5.0RC1   Edit
Assignee: Adrian Colyer CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-06-22 12:35 EDT by Jim Fontana CLA
Modified: 2005-12-01 10:33 EST (History)
0 users

See Also:


Attachments
JSP generated .java file (506.59 KB, text/plain)
2005-06-22 12:37 EDT, Jim Fontana CLA
no flags Details
woven class file (350.38 KB, application/octet-stream)
2005-06-22 12:38 EDT, Jim Fontana CLA
no flags Details
Aspect being woven (37.39 KB, text/plain)
2005-06-22 12:40 EDT, Jim Fontana CLA
no flags Details
Stack trace. (1.03 KB, text/plain)
2005-06-22 12:47 EDT, Jim Fontana CLA
no flags Details
zip containing classes which attempt to recreate the problem (42.66 KB, application/zip)
2005-11-30 12:04 EST, Helen Beeken CLA
no flags Details
class which recreates the verify error with aspectj 1.2.1 (5.77 KB, application/octet-stream)
2005-12-01 07:59 EST, Helen Beeken CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jim Fontana CLA 2005-06-22 12:35:38 EDT
When weaving a precompiled JSP, get a runtime VerifyError - "register xxx 
contains wrong type."  The woven byte code decompiles incorrectly.  This 
appears to be like bug #72528.
Comment 1 Jim Fontana CLA 2005-06-22 12:37:28 EDT
Created attachment 23753 [details]
JSP generated .java file
Comment 2 Jim Fontana CLA 2005-06-22 12:38:32 EDT
Created attachment 23754 [details]
woven class file
Comment 3 Jim Fontana CLA 2005-06-22 12:40:15 EDT
Created attachment 23755 [details]
Aspect being woven
Comment 4 Jim Fontana CLA 2005-06-22 12:47:49 EDT
Created attachment 23756 [details]
Stack trace.
Comment 5 Adrian Colyer CLA 2005-08-26 11:30:06 EDT
investigate in M4
Comment 6 Adrian Colyer CLA 2005-10-28 06:38:17 EDT
has to be investigated before 1.5.0 RC1
Comment 7 Andrew Clement CLA 2005-11-30 11:37:38 EST
Helen looked into this one Adrian ... and made some useful observations about the code.  I'll get her to append.
Comment 8 Helen Beeken CLA 2005-11-30 12:02:32 EST
Googling on the verify error I found that when someone saw the following error:

[java] java.lang.VerifyError: (class: com/athico/rp/entityDefinitions/Address, method: setNumber signature: (I)V) Register 1 contains wrong type

it was because in the bytecode they should have had ILOAD, not ALOAD as it was an integer not a reference.

ALOAD = load a reference from a local variable
ILOAD = load an int from a local variable.

I also tried to write a testcase which would produce bytecode similar to the appended class file. What I found was that there is around advice on a method, in this case the around advice affects execution(public void *._jspService(..)). Then, within the execution of _jspService(..) there are calls to "write(..)" which are affected by other around advice. I'll attach a zip of the classes I created. Unfortunately, although the byte code was similar, I couldn't reproduce the verify error. To reproduce I tried the following scenarios (all on the command line):

* compile the 3 classes with javac 
* create a jar with these 3 class files in it
* weave the aspect with the jar file
* run the output (I added a main method to left_jsp.java)

I did this both with java 1.4 and java 5, and with an aspectj 1.2.1 and the latest development build. In all cases I couldn't reproduce it.

I also did a quick look through the bytecode of the supplied class file and couldn't see anything which struck me that was an ALOAD which should have been an ILOAD.
Comment 9 Helen Beeken CLA 2005-11-30 12:04:10 EST
Created attachment 30877 [details]
zip containing classes which attempt to recreate the problem

As mentioned in my above comment, this is a zip of the classes and aspect I created to try to recreate the problem.
Comment 10 Adrian Colyer CLA 2005-11-30 13:58:22 EST
I've been looking into this one too today (on the train). Bit of a needle in a haystack, but there were some clues lurking. We know it's a problem with the contents of register 195, and we know it's in the jspService method. If you look at uses of that register within the method, there are a few bunched together that look  ok, and then later on out of the blue you see:

iinc 195,1 

when none of the surrounding code is referencing that register.

The other clue is that this is a generated method with a very big body - necessitating the need for wide instructions. Furthermore, we suspect here the classic situation whereby the addition of advice instructions pushes instructions further down the method body over the single-byte barrier.

So here's the fragment of suspicious bytecode:

   6778:	aload_w 515
   6782:	invokevirtual	#230; // MenuDO.getItems:()Ljava/util/Set;
   6785:	invokeinterface	#231,  1; // java/util/Set.size:()I
   6790:	istore_w 451
   6794:	aload_w 437
   6798:	aload_w 515
   6802:	invokevirtual	#239; // MenuDO.getId:()Ljava/lang/Integer;
   6805:	invokevirtual	#246; //ArrayList.add:(Ljava/lang/Object;)Z
   6808:	pop
   6809:	new	#9; //class java/lang/Integer
   6812:	dup
   6813:	aload_0
   6814:	getfield	#14; //Field menuItemSpacing:I
==>   6817:	iinc	195, 1
   6820:	iload_w 451
   6824:	imul
   6825:	aload_0
   6826:	getfield	#15; //Field menuExpandedHeight:I
   6829:	iadd
   6830:	invokespecial	#10; //Method java/lang/Integer."<init>":(I)V

with the offending instruction highlighted. Observe the magic formula:

195 + 256 = 451!

so we tried to iinc 451, but instead of using a wide instruction, used a normal instruction thus dropping the high bit and giving iinc 195.

This bytecode comes from the source code fragment:

itemCount = menuForSize.getItems().size();
idList.add(menuForSize.getId());

// calculate the height of the menu
Integer height = new Integer(menuItemSpacing * ++itemCount +  
                             menuExpandedHeight);
heightList.add(height);

it's the "++itemCount" that's causing the problem.

So the diagnosis is....

the original compiled code had an iinc xxx,1 instruction. We wove into the method body, and on rewriting failed to correctly generate and iinc_w instruction and instead generated an iinc instruction. I suspect this is a bug in BCEL (last time I ran into something similar that's where the problem was).

Next step is to try and recreate locally. A program containing a method of the form:

public void foo() {
  int i1 = 1;
  int i2 = ++i1;
  int i3 = ++i2;
  ....
  int i256 = ++i255;
}

and then compiled with the -preserveAllLocals flag should do it. We can then weave that method and try to run the result - if my analysis is correct this will produce the same verify error. Then it's a simple matter of tracking into BCEL and watching the IINC instruction get updated and written out.

Helen: I'm at a meeting in London again all day tomorrow - could you please try generating a class like the above and testing out my hypothesis?

Thanks, Adrian.
Comment 11 Adrian Colyer CLA 2005-11-30 14:07:01 EST
One last clue for a hopeful fix tomorrow:

A quick look at IINC in BCEL (org.aspectj.apache.bcel.generic.IINC) reveals what looks to be a likely source of the bug. IINC has it's own calculation of wide, but the superclass LocalVariableInstruction has a separate (private final) method that tests for wideness based on a different criteria. When writing the bytes out, it is the superclass's test for wide that is used rather than the IINC one. Doesn't look right to me on a first glance. 

Andy / Helen - reckon this might be enough to go on for you to put in a fix for this tomorrow for me?
Comment 12 Andrew Clement CLA 2005-11-30 14:28:27 EST
yes - sounds the likely problem - fix should be no probs.  Good detective work ;)
Comment 13 Adrian Colyer CLA 2005-11-30 14:53:05 EST
one last thought.... the test program I suggested probably won't recreate the verify error (though examining the generated bytecode would still show the flaw) - since all the vars are ints. Try making the earlier vars Objects, and then put an int var with a ++ instruction on the end of the list....
Comment 14 Helen Beeken CLA 2005-12-01 07:59:53 EST
Created attachment 30933 [details]
class which recreates the verify error with aspectj 1.2.1

Compiling the attached class using "ajc -preserveAllLocals C2.java", then weaving the generate classfile with the following aspect:

public aspect A {

	pointcut p() : execution(public void C2.foo(..));
	
	void around() : p() {
		proceed();
	}
}

I found the following:

- with aspectj version 1.2.1 (which is what this bug was raised with) I recreated the verify error when running the class and the generated output is as Adrian describes:

   1627:	aload_1
   1628:	invokeinterface	#44,  1; //InterfaceMethod java/util/List.size:()I
   1633:	istore_w 387
   1637:	new	#46; //class java/lang/Integer
   1640:	dup
   1641:	aload_0
   1642:	getfield	#14; //Field menuItemSpacing:I
   1645:	iinc	131, 1                                 <=== incorrect 
   1648:	iload_w 387
   1652:	imul
   1653:	aload_0
   1654:	getfield	#16; //Field menuExpandedHeight:I
   1657:	iadd
   1658:	invokespecial	#49; //Method java/lang/Integer."<init>":(I)V

- with aspectj version 1.5.0M5 I'm unable to recreate the verify error and the generated output is as expected:

   1819:	aload_1
   1820:	invokeinterface	#44,  1; //InterfaceMethod java/util/List.size:()I
   1825:	istore_w 387
   1829:	new	#46; //class java/lang/Integer
   1832:	dup
   1833:	aload_0
   1834:	getfield	#14; //Field menuItemSpacing:I
   1837:	iinc_w 387, 1                                  <=== as expected
   1843:	iload_w 387
   1847:	imul
   1848:	aload_0
   1849:	getfield	#16; //Field menuExpandedHeight:I
   1852:	iadd
   1853:	invokespecial	#49; //Method java/lang/Integer."<init>":(I)V

Looking at the resource history for IINC.java, it looks like this was fixed as part of bug 106130.
Comment 15 Andrew Clement CLA 2005-12-01 10:33:34 EST
As we discovered (finally...) this is already fixed in AspectJ5 ...

*** This bug has been marked as a duplicate of 106130 ***