javajvmbytecodebcel

Illegal constant pool index for method signature when creating a simple class file


I want to create a simple compiler which generates Java Bytecode. For generating the code I am using the Apache BCEL library.

However, I failed in creating a simple class with a main method that does nothing. I use the following code (I know that it is Scala, but that's not so important, as you'll see later) for generating the class file:

private def generateClassFile(): Unit =
{
    // JVM tutorial: https://commons.apache.org/proper/commons-bcel/manual/jvm.html
    val interfaces: Array[String] = new Array(0);
    classFactory = new ClassGen(
        "MiniPascal",
        "java.lang.Object",
        null,
        Const.ACC_PUBLIC | Const.ACC_SUPER,
        interfaces
    );

    val mainConstantPool: ConstantPoolGen = new ConstantPoolGen();
    val mainMethod = generateMainMethod(mainConstantPool);
    classFactory.addMethod(mainMethod.getMethod());
}

private def generateMainMethod(mainConstantPool): MethodGen =
{
    val instructions = new InstructionList();
    instructions.append(InstructionConstants.NOP);

    mainConstantPool.addNameAndType("main", "([java/lang/String;)V");

    val methodArgumentNames = Array("args");
    val methodArgumentTypes: Array[Type] = Array(new ArrayType(Type.STRING, 1));
    val mainMethod: MethodGen = new MethodGen(
        Const.ACC_PUBLIC | Const.ACC_STATIC,
        Type.VOID,
        methodArgumentTypes,
        methodArgumentNames,
        "main", "MiniPascal",
        instructions,
        mainConstantPool
    );

    return mainMethod;
}

private def saveClassFile(): Unit =
{
    val classFile: JavaClass = classFactory.getJavaClass();
    classFile.dump("MiniPascal.class");
    //println(classFile.toString());
}

When running the program the class file is generated, however when executing java MiniPascal I get the following exception:

java.lang.ClassFormatError: Illegal constant pool index 4 for method signature in class file MiniPascal

I read about the Java Bytecode and know that the constant pool is about 60% of the content of a class file and stores the name's of all literals, but I haven't figure out the case of the exception yet.

I am looking forward to your suggestions. Thanks for your help!


Solution

  • You're creating your own empty constant pool that you don't associate with the class, using line:

    val mainConstantPool: ConstantPoolGen = new ConstantPoolGen();
    

    So although you add the method signature to the constant pool, it doesn't work because the constant pool is never added to the class file.

    Either create the constant pool first and pass it to the ClassGen constructor as the last argument, or initialize mainConstantPool from classFactory.getConstantPool().