Hello Stephen,

Thursday, June 12, 2003, 1:06:25 PM, you wrote:

  So... Can you change code in CVS to fix this?

SK> I found the problem (again:)), and posting this so anybody interested
SK> can read from one place.
SK> Last time I did not noticed the setSize() invokation from within 
SK> initFromFile.
SK> What happens:
SK> setSize() makes the proper length and changes the opcode (hmm, I am not 
SK> sure I want BCEL to change compiled code without my confirmation, but 
SK> who cares!). The next line in the initFromFile _restores_ the old opcode 
SK> (LDC_W), thus making opcode and length inconsistent. The problem shows 
SK> only when compiled code contains LDC_W with index less than MAX_BYTE 
SK> (when LDC suffice), and, therefore, shows up very rarely.

SK> Konstantin Scheglov wrote:

>>Hello Stephen,
>>
>>Thursday, June 12, 2003, 11:56:21 AM, you wrote:
>>
>>SK> Kosja, we are strange guys.
>>SK> Who checked the bug reports?
>>SK> Nobody...
>>SK> But should:
>>SK> http://nagoya.apache.org/bugzilla/show_bug.cgi?id=18323
>>  Ok, thanks. But to find this bug I should already to know, what to
>>search. :-)
>>
>>SK> (I investigated the code. Actually nobody invokes setSize(), when 
>>SK> reading from file; and NOONE sets proper length of LDC_W, when reading 
>>SK> from file (i think), and it stays 0 all the time. The fix you made in 
>>SK> dump() forces dumping with proper length  for the proper instruction).
>>  LDC_W.initFromFile calls LDC.setIndex, which call LDC.setSize()
>>  Well, may be my fix is not enough, it just dumps right bytes, but
>>length is still wrong.
>>  As I can see, there was version 1.2 of LDC_W with:
>>    opcode = org.apache.bcel.Constants.LDC_W;
>>    length = 3;
>>  but in 1.3 there was "bug fix" and length change was removed.
>>
>>SK> Strange, I have passed near a MB bytecode through BCEL, and had never 
>>SK> seen this bug in action.
>>  Yes, I and users of my tool also process many MB of code, but
>>as you can see, sometimes this happens. I have sample class (about 500
>>bytes length). Most probably this class also was automatically
>>generated, and generator is not smart enough to use LDC when index is
>>small, so it uses LDC_W and this causes problem. I think javac/jikes
>>use LDC where this is possible, so you just never see such cases.
>>
>>SK> About method copy:
>>SK> class Class1 {
>>SK> void method1() {
>>SK> // getstatic <System.out>
>>SK> // ldc #3 <String "Hello world">!!!!!
>>SK> // invokevirtual <PrintStream::println(String)>
>>SK> // return
>>SK> }
>>SK> }
>>
>>SK> if you want to copy method1 to _another_ class, you have to make sure 
>>SK> that ldc "Hello world" points somewhere in the new constantpool where 
>>SK> you have "Hello world". Complications are pouring in when you want the 
>>SK> copied method to reference methods of its containing class; or to 
>>SK> checkcast if a reference points to instance of the enclosing class.
>>  Thank you.
>>  I just replace methods in each class with a little changed methods,
>>so I think, that changing of constant pool is not required.
>>
>>SK> Konstantin Scheglov wrote:
>>
>>  
>>
>>>>Hello Stephen,
>>>>
>>>>Wednesday, June 11, 2003, 7:11:16 PM, you wrote:
>>>>
>>>> Ok, now I am sure, that this is bug in BCEL.
>>>>
>>>> Here is code from LDC_W:
>>>> protected void initFromFile(ByteSequence bytes, boolean wide)
>>>>      throws IOException
>>>> {
>>>>   setIndex(bytes.readUnsignedShort());
>>>>   // Override just in case it has been changed
>>>>   opcode = org.apache.bcel.Constants.LDC_W;
>>>> }
>>>> As you can see, it forces instruction code to LDC_W.
>>>>
>>>> And here is code from LDC:
>>>> public final void setIndex(int index) {
>>>>   super.setIndex(index);
>>>>   setSize();
>>>> }
>>>> protected final void setSize() {
>>>>   if(index <= org.apache.bcel.Constants.MAX_BYTE) { // Fits in one byte?
>>>>     opcode = org.apache.bcel.Constants.LDC;
>>>>     length = 2;
>>>>   } else {
>>>>     opcode = org.apache.bcel.Constants.LDC_W;
>>>>     length = 3;
>>>>   }
>>>> }
>>>>
>>>> I.e. setSize() changes inscruction code and length. Then, length
>>>>used in dump() to detect, that byte or short argument is needed:
>>>> public void dump(DataOutputStream out) throws IOException {
>>>>   out.writeByte(opcode);
>>>>   if(length == 2)
>>>>     out.writeByte(index);
>>>>   else // Applies for LDC_W
>>>>     out.writeShort(index);
>>>> }
>>>>
>>>> But we have (in my case) length == 2, i.e. one byte and LDC_W
>>>>instruction! So, when it tryies to create String for this instruction,
>>>>it reads one random byte (in reallity next instruction)!
>>>>
>>>> When I change dump() to this code, I receive no exceptions.
>>>>
>>>> public void dump(DataOutputStream out) throws IOException {
>>>>   out.writeByte(opcode);
>>>>   if(opcode == org.apache.bcel.Constants.LDC)
>>>>     out.writeByte(index);
>>>>   else // Applies for LDC_W
>>>>     out.writeShort(index);
>>>> }
>>>>
>>>> 
>>>>
>>>>SK> The code you sent is OK, at least for BCEL 5.0 and 5.1 (I have 
>>>>SK> experience with those). The problem is elsewere.
>>>>SK> Btw, did you checked if your original (not instrumented) classes are 
>>>>SK> acceptible? It is so stupid mistake, that you have to be genious to 
>>>>SK> avoid it, at least I can not :))).
>>>>SK> Beside this: if you copy method from one class to another (i do not what 
>>>>SK> are your real application), you must change the constant pool indices of 
>>>>SK> the instructions.
>>>>
>>>>SK> Konstantin Scheglov wrote:
>>>>
>>>> 
>>>>
>>>>      
>>>>
>>>>>>I use following code to instrument one class.
>>>>>>But when I instrument some classes and try to print debug
>>>>>>information, I receive following exception.
>>>>>>
>>>>>>org.apache.bcel.classfile.ClassFormatException: Invalid constant pool reference: 
>>>>>>28088. Constant pool size is: 1024
>>>>>>      at 
>>>>>> org.apache.bcel.classfile.ConstantPool.getConstant(ConstantPool.java:242)
>>>>>>      at org.apache.bcel.classfile.Utility.codeToString(Utility.java:369)
>>>>>>      at org.apache.bcel.classfile.Utility.codeToString(Utility.java:166)
>>>>>>      at org.apache.bcel.classfile.Code.toString(Code.java:326)
>>>>>>      at org.apache.bcel.classfile.Code.toString(Code.java:352)
>>>>>>      at java.lang.String.valueOf(String.java:2131)
>>>>>>      at java.io.PrintStream.print(PrintStream.java:462)
>>>>>>      at java.io.PrintStream.println(PrintStream.java:599)
>>>>>>      at 
>>>>>> ru.nlmk.eclipse.plugins.profiler.trace.Trace.instrumentClass(Trace.java:1190)
>>>>>>      at 
>>>>>> ru.nlmk.eclipse.plugins.profiler.trace.test.TestBCEL.main(TestBCEL.java:23)
>>>>>>
>>>>>>
>>>>>>As you can see, I just copy code from one method to another (in real application
>>>>>>I change code a little). And when I try to load this class in real application
>>>>>>I receive exception like this from JVM:  "VerifyError: Illegal constant pool 
>>>>>>index".
>>>>>>
>>>>>>
>>>>>>      public static JavaClass instrumentClass(JavaClass clazz) throws Exception {
>>>>>>              ClassGen classGen = new ClassGen(clazz);
>>>>>>              ConstantPoolGen cp = new ConstantPoolGen(clazz.getConstantPool());
>>>>>>              classGen.setConstantPool(cp);
>>>>>>              //
>>>>>>              for (int i = 0; i < clazz.getMethods().length; i++) {
>>>>>>                      Method method = clazz.getMethods()[i];
>>>>>>                      if (method.isAbstract() || method.isNative())
>>>>>>                              continue;
>>>>>>                      if (method.getName().equals("finalize"))
>>>>>>                              continue;
>>>>>>                      MethodGen mg = new MethodGen(method, clazz.getClassName(), 
>>>>>> cp);
>>>>>>                      mg.setConstantPool(cp);
>>>>>>                      Method newMethod = mg.getMethod();
>>>>>>                      if (m_Debug) {
>>>>>>                              System.out.println(method.getCode());
>>>>>>                              System.out.println(newMethod.getCode());
>>>>>>                      }
>>>>>>                      classGen.replaceMethod(method, newMethod);
>>>>>>              }
>>>>>>              //
>>>>>>              JavaClass newClazz = classGen.getJavaClass();
>>>>>>              newClazz.setConstantPool(cp.getFinalConstantPool());
>>>>>>              return newClazz;
>>>>>>      }
>>>>>>
>>>>>>What I do wrong?
>>>>>>I see such exception only on few classes (methods).
>>>>>>I have example of such class.
>>>>>>      
>>>>>>
>>>>>>
>>>>>>
>>>>>>     
>>>>>>
>>>>>>          
>>>>>>
>>>>
>>>>SK> ---------------------------------------------------------------------
>>>>SK> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>>>SK> For additional commands, e-mail: [EMAIL PROTECTED]
>>>>
>>>>
>>>>
>>>> 
>>>>
>>>>      
>>>>
>>
>>
>>
>>
>>  
>>




-- 
Best regards,
 Konstantin                            mailto:[EMAIL PROTECTED]


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to