Razvanica | 25 May 2009 19:50
Picon
Favicon

ArrayIndexOutOfBoundsException in generic.PUTFIELD


Hello all,

Here's my problem. I am trying to make some network simulations using a tool
called JiST/SWANS. This simulator has been written for Java 1.4 and, for my
simulations, I would like to use some 1.5 features, like genericity. 

So what I am trying to do is to compile the original code with the "source
-1.5" tag instead of the "source -1.4" tag. The problem is that the
simulator uses bcel to rewrite the bytecode so that JVM could be used for
simulations. The bcel library in the release doesn't work with the "source
-1.5" tag so I replace it with bcel-5.2. I made 2 minor modifications to the
original code :
- I have added an implementation of getClassPath in a class that implements
org.apache.bcel.util.Repository. This class just returns null, just like in
org.apache.bcel.util.ClassLoaderRepository
- In a class using org.apache.bcel.Repository.lookupClass() I am now
throwing java.lang.ClassNotFoundException 

These 2 modifications shouldn't change anything as far as I understand the
application. And when I compile the new code with the "-source 1.4" tag, it
doesn,t change anything. Everything compiles and works just fine. However,
when I compile the new code with the "-source 1.5" tag the compilation goes
smoothly, but, at runtime, the rewriter throws an
ArrayIndexOutOfBoundsException.

This happens every time org.apache.bcel.generic.PUTFIELD.accept is called:
java.lang.ArrayIndexOutOfBoundsException: -1 
   at java.util.ArrayList.remove(ArrayList.java:390)
   at
(Continue reading)

Arrin Daley | 26 May 2009 03:48
Picon
Picon

Re: ArrayIndexOutOfBoundsException in generic.PUTFIELD

Hi

My experience is that the error you are getting is it because some 
method code has an invalid stack, in this case you are removing too many 
items from the stack, the verifier is picking this up and reporting the 
error. I'm not sure but perhaps some code doesn't call 
MethodGen.setMaxStack() after transforming, although I doubt it, because 
if the code were otherwise correct it should have complained of a stack 
overflow.

The problem has to be with the method it is verifying at the time so if 
you can print out which method the verifier is working on and it's 
bytecodes you could go through it and find the problem. The bytecode 
pre-transformation by BCEL should be correct so the problem lies with 
the transformations your code performs.

I'm don't know why this should be a problem with 1.5 and not 1.4.

Hope it helps

Bye Arrin

Razvanica wrote:
> Hello all,
>
> Here's my problem. I am trying to make some network simulations using a tool
> called JiST/SWANS. This simulator has been written for Java 1.4 and, for my
> simulations, I would like to use some 1.5 features, like genericity. 
>
> So what I am trying to do is to compile the original code with the "source
(Continue reading)

Razvanica | 26 May 2009 15:24
Picon
Favicon

Re: ArrayIndexOutOfBoundsException in generic.PUTFIELD


Hello Arrin, 

Thank you for your response. I found the method that fails and it's true
that the bytecode resulting after compiling with the "-source 1.4" flag and
the one that result when I compile with the "-source 1.5" are very
different. Unfortunately for me, I don't have the skills required to judge
what exactly triggers the exception I was talking about (I understand I try
to pop from an empty stack but I haven't yet figured what exactly should be
on that stack). I will post here the 2 bytecodes, hoping you or someone else
would be able to detect the problem. 

The bytecode that works (generated with "-source 1.4") is:
public void _jistPostInit();
  Code:
   0:	aload_0
   1:	getstatic	#24; //Field
jist/runtime/JistAPI.THIS:Ljist/runtime/JistAPI$Entity;
   4:	getstatic	#25; //Field
class$jist$swans$app$AppInterface$UdpApp:Ljava/lang/Class;
   7:	ifnonnull	22
   10:	ldc	#26; //String jist.swans.app.AppInterface$UdpApp
   12:	invokestatic	#27; //Method
class$:(Ljava/lang/String;)Ljava/lang/Class;
   15:	dup
   16:	putstatic	#25; //Field
class$jist$swans$app$AppInterface$UdpApp:Ljava/lang/Class;
   19:	goto	25
   22:	getstatic	#25; //Field
class$jist$swans$app$AppInterface$UdpApp:Ljava/lang/Class;
(Continue reading)

Arrin Daley | 29 May 2009 02:16
Picon
Picon

Re: ArrayIndexOutOfBoundsException in generic.PUTFIELD

Hi Razvan

If you use the BCEL APIs you can see what effect each bytecode will have on the stack (it's amongst the first
lines explaining each bytecode), the stack is initially empty and the arguments are in the ALOAD_0,
ILOAD1 etc slots.
Anyway I've gone through and produced an idea of what the stack does for each method below, there appears to
be a couple of problems the LDC_W doesn't seem right LDC_W is typically for loading wide constants such as
double and long from the constantPool, second we end up with the result of an ALOAD_0 still on the stack at
the end of the execution of the method which shouldn't happen either. Neither of these really explain how
you are getting a StackUnderflow problem as these are both putting too much on the stack. Anyway they are
worth fixing, and perhaps it creates trouble further down the line?

Bye Arrin

Code:
   0:	aload_0
obj,
   1:	getstatic	#19; //Field jist/runtime/JistAPI.THIS:Ljist/runtime/JistAPI$Entity;
obj, obj
   4:	ldc_w	#20; //class jist/swans/app/AppInterface$UdpApp
obj, obj, w1, w2,
   7:	invokestatic	#21; //Method jist/runtime/JistAPI.proxy:(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
1st problem here the last thing put on the stack was the result of the LDC_W(a wide type constant, like a long
or a double) but the invokestatic is expecting 2 objects. 
Perhaps it's supposed to be an LDC? I'll continue as though it is... obj, obj, Class

obj, obj, obj
   10:	checkcast	#20; //class jist/swans/app/AppInterface$UdpApp
obj, obj, obj
   13:	invokeinterface	#22,  1; //InterfaceMethod jist/swans/app/AppInterface$UdpApp.getUdpEntity:()Ljist/swans/trans/TransInterface$TransUdpInterface;
(Continue reading)


Gmane