1

I have succeeded in dumping dynamically generated bytecodes to a file using ASM, but fail to load it. The error message is:

java.lang.ClassFormatError: JVMCFRE102 field signature invalid; class=TGWD, offset=0
    at java.lang.ClassLoader.defineClass(ClassLoader.java:364)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:284)
    at java.lang.invoke.ByteCodeClassLoader.run(ByteCodeClassLoader.java:20)

The BytecodeClassLoader is a Class I wrote here. The javap -v result is also shown below.

Classfile /C:/temp/TGWD.class
  Last modified Mar 10, 2015; size 750 bytes
  MD5 checksum 462ec39a439ab0d30c676eb92a93fd5a
public class TGWD extends java.lang.invoke.BaseTemplate
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER

Constant pool:
   #1 = Utf8               TGWD
   #2 = Class              #1             //  TGWD
   #3 = Utf8               java/lang/invoke/BaseTemplate
   #4 = Class              #3             //  java/lang/invoke/BaseTemplate
   #5 = Utf8               guard
   #6 = Utf8               Ljava/lang/invoke/MethodHandle;
   #7 = Utf8               trueTarget
   #8 = Utf8               falseTarget
   #9 = Utf8               <init>
  #10 = Utf8               (Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V
  #11 = Utf8               java.lang.invoke.MethodHandle
  #12 = NameAndType        #5:#11         //  guard:java.lang.invoke.MethodHandle
  #13 = Fieldref           #2.#12         //  TGWD.guard:java.lang.invoke.MethodHandle
  #14 = NameAndType        #7:#11         //  trueTarget:java.lang.invoke.MethodHandle
  #15 = Fieldref           #2.#14         //  TGWD.trueTarget:java.lang.invoke.MethodHandle
  #16 = NameAndType        #8:#11         //  falseTarget:java.lang.invoke.MethodHandle
  #17 = Fieldref           #2.#16         //  TGWD.falseTarget:java.lang.invoke.MethodHandle
  #18 = Utf8               eval
  #19 = Utf8               ()V
  #20 = Utf8               Hello
  #21 = Utf8               (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
  #22 = Utf8               java/lang/Throwable
  #23 = Class              #22            //  java/lang/Throwable
  #24 = NameAndType        #5:#6          //  guard:Ljava/lang/invoke/MethodHandle;
  #25 = Fieldref           #2.#24         //  TGWD.guard:Ljava/lang/invoke/MethodHandle;
  #26 = Utf8               java/lang/invoke/MethodHandle
  #27 = Class              #26            //  java/lang/invoke/MethodHandle
  #28 = Utf8               invokeExact
  #29 = Utf8               (Ljava/lang/String;)Z
  #30 = NameAndType        #28:#29        //  invokeExact:(Ljava/lang/String;)Z
  #31 = Methodref          #27.#30        //  java/lang/invoke/MethodHandle.invokeExact:(Ljava/lang/String;)Z
  #32 = NameAndType        #7:#6          //  trueTarget:Ljava/lang/invoke/MethodHandle;
  #33 = Fieldref           #2.#32         //  TGWD.trueTarget:Ljava/lang/invoke/MethodHandle;
  #34 = NameAndType        #28:#21        //  invokeExact:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
  #35 = Methodref          #27.#34        //  java/lang/invoke/MethodHandle.invokeExact:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
  #36 = NameAndType        #8:#6          //  falseTarget:Ljava/lang/invoke/MethodHandle;
  #37 = Fieldref           #2.#36         //  TGWD.falseTarget:Ljava/lang/invoke/MethodHandle;
  #38 = Utf8               Code
  #39 = Utf8               StackMapTable
  #40 = Utf8               Exceptions
{
  final java.lang.invoke.MethodHandle guard;
    flags: ACC_FINAL


  final java.lang.invoke.MethodHandle trueTarget;
    flags: ACC_FINAL


  final java.lang.invoke.MethodHandle falseTarget;
    flags: ACC_FINAL


  public TGWD(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
    flags: ACC_PUBLIC, ACC_VARARGS

    Code:
      stack=0, locals=4, args_size=4
         0: aload_0       
         1: aload_1       
         2: bipush        0
         4: aaload        
         5: putfield      #13                 // Field guard:java.lang.invoke.MethodHandle
         8: aload_0       
         9: aload_1       
        10: bipush        1
        12: aaload        
        13: putfield      #15                 // Field trueTarget:java.lang.invoke.MethodHandle
        16: aload_0       
        17: aload_1       
        18: bipush        2
        20: aaload        
        21: putfield      #17                 // Field falseTarget:java.lang.invoke.MethodHandle
        24: return        

  public void eval();
    flags: ACC_PUBLIC

    Code:
      stack=0, locals=1, args_size=1
         0: return        

  public java.lang.String Hello(java.lang.String, java.lang.String) throws java.lang.Throwable;
    flags: ACC_PUBLIC

    Code:
      stack=0, locals=3, args_size=3
         0: aload_0       
         1: getfield      #25                 // Field guard:Ljava/lang/invoke/MethodHandle;
         4: aload_1       
         5: invokevirtual #31                 // Method java/lang/invoke/MethodHandle.invokeExact:(Ljava/lang/String;)Z
         8: ifeq          21
        11: aload_0       
        12: getfield      #33                 // Field trueTarget:Ljava/lang/invoke/MethodHandle;
        15: aload_1       
        16: aload_2       
        17: invokevirtual #35                 // Method java/lang/invoke/MethodHandle.invokeExact:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
        20: areturn       
        21: aload_0       
        22: getfield      #37                 // Field falseTarget:Ljava/lang/invoke/MethodHandle;
        25: aload_1       
        26: aload_2       
        27: invokevirtual #35                 // Method java/lang/invoke/MethodHandle.invokeExact:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
        30: areturn       
      StackMapTable: number_of_entries = 1
           frame_type = 21 /* same */

    Exceptions:
      throws java.lang.Throwable
}

Can i anyone have an idea where is wrong in the generated bytecodes? Thanks. I also attached the class file hereClass File..

Below information maybe useful: 1, According to the stack, i guess the problem is at three field members. I use below code to generate these fields:

FieldVisitor fv;
fv = cw.visitField(ACC_FINAL, 'guard', "Ljava/lang/..", null, null);
fv.visitEnd();

I change ACC_FINAL to the ACC_PRIVATE. The result is the same except none of three field member is shown in javap -v result.

2, The Base class BaseTemplate is an empty abstract class defined as:

public abstract class BaseTemplate { }

============================== Update:

After changing the putfield instruction in my original code from

mv.visitFieldInsn(PUTFIELD, className, list.get(i).name(), list.get(i).type());

to

mv.visitFieldInsn(PUTFIELD, className, list.get(i).name(),Utils.getFieldDesc(list.get(i).type()));, the class loading succeeds now. The reason is that wronlg field signature set(as in @Holger answers).

shijie xu
  • 1,975
  • 21
  • 52
  • Please pay attention to the tags you use. `" **NOTE**: For Java ASM, use the tag [java-asm] instead."` – Jonathon Reinhart Mar 11 '15 at 04:49
  • The class file you have linked is not the same as you have shown above, the MD5 sums do not match. Mind the `-private` option of `javap`… – Holger Mar 11 '15 at 09:16

1 Answers1

1

You generated your constructor using "java.lang.invoke.MethodHandle" as the field signature rather than the correct "Ljava/lang/invoke/MethodHandle;". This can be seen in the javap output by the lines:

     5: putfield      #13             // Field guard:java.lang.invoke.MethodHandle
…
    13: putfield      #15             // Field trueTarget:java.lang.invoke.MethodHandle
…
    21: putfield      #17             // Field falseTarget:java.lang.invoke.MethodHandle

whereas the Hello method correctly uses:

     1: getfield      #25             // Field guard:Ljava/lang/invoke/MethodHandle;
…
    12: getfield      #33             // Field trueTarget:Ljava/lang/invoke/MethodHandle;
…
    22: getfield      #37             // Field falseTarget:Ljava/lang/invoke/MethodHandle;

This also explains the rather big constant pool. Item #11 contains the wrong java.lang.invoke.MethodHandle signature which is then used by the followup items #12 - #17 which are used by the constructor. These are distinct from the items #25, #33, and #37 used in the Hello method. In a correctly generated class, these instructions share the same items in the constant pool (which all refer indirectly to the correct signature Ljava/lang/invoke/MethodHandle; which is stored in item #6 in this class file.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • Thanks. This fixes my problem as what i have updated in the first post. The following problem is that stack size is wrongly calculated in the generated bytecode (It should be 2 for constructor instead of 0). A simplified with more information is at http://stackoverflow.com/questions/28988694/wrong-stack-size-calculated-by-asm-library – shijie xu Mar 11 '15 at 14:28