Не удалось загрузить динамически сгенерированные байт-коды

Мне удалось сбросить динамически сгенерированные байт-коды в файл с помощью ASM, но не удалось загрузить его. Сообщение об ошибке:

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)

BytecodeClassLoader это класс, который я написал здесь. Результат javap -v также показан ниже.

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
}

Можно ли у кого-нибудь понять, что не так в сгенерированных байт-кодах? Благодарю. Я также прикрепил файл класса здесь Class File..

Ниже информация может быть полезна: 1, в зависимости от стека, я думаю, проблема в трех участниках поля. Я использую код ниже для генерации этих полей:

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

я меняю ACC_FINAL к ACC_PRIVATE, Результат тот же, за исключением того, что ни один из трех членов поля не отображается в javap -v результат.

2, Базовый класс BaseTemplate пустой абстрактный класс, определенный как:

public abstract class BaseTemplate { }

============================== Обновление:

После изменения инструкции putfield в моем исходном коде из

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

в

mv.visitFieldInsn(PUTFIELD, className, list.get(i).name(),Utils.getFieldDesc(list.get(i).type()));загрузка класса теперь успешна. Причина в том, что wronlg поле подписи установлено (как в @Holger ответы).

1 ответ

Решение

Вы сгенерировали свой конструктор используя "java.lang.invoke.MethodHandle" в качестве подписи поля, а не правильной "Ljava/lang/invoke/MethodHandle;", Это можно увидеть в javap вывод по строкам:

     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

тогда как Hello метод правильно использует:

     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;

Это также объясняет довольно большой постоянный пул. Пункт № 11 содержит неправильный java.lang.invoke.MethodHandle подпись, которая затем используется в последующих элементах #12 - #17, которые используются конструктором. Они отличаются от предметов № 25, № 33 и № 37, используемых в Hello метод. В правильно сгенерированном классе эти инструкции совместно используют одни и те же элементы в пуле констант (которые все косвенно относятся к правильной сигнатуре Ljava/lang/invoke/MethodHandle; который хранится в пункте № 6 в этом файле класса.

Другие вопросы по тегам