Search code examples
javajvmjava-bytecode-asm

JVM: Invalid index 1 in LocalVariableTable


I am trying to compile the following code using a custom compiler:

public static void main([String] args)
{
    long i = 2L
    i *= 2L
    System out println i
}

The result of the compilation is, when using javap, this Bytecode:

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=2, args_size=1
         0: ldc2_w        #14                 // long 2l
         3: lstore_1      
         4: lload_1       
         5: ldc2_w        #14                 // long 2l
         8: lmul          
         9: lstore_1      
        10: getstatic     #21                 // Field java/lang/System.out:Ljava/io/PrintStream;
        13: lload_1       
        14: invokevirtual #27                 // Method java/io/PrintStream.println:(J)V
        17: return        
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      17     1     i   J
            0      17     0  args   [Ljava/lang/String;
    MethodParameters:
      Name                           Flags
      args

However, when I try to run the Bytecode, the JVM throws a ClassFormatError that reads Invalid index 1 in LocalVariableTable. Is this related to the fact that in the LocalVariableTable, slot 1 comes before slot 0?

EDIT:

If I change the long variable to an int, the JVM does not complain at all, even if the LocalVariableTable is still unsorted:

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: iconst_2      
         1: istore_1      
         2: iload_1       
         3: iconst_2      
         4: imul          
         5: istore_1      
         6: getstatic     #19                 // Field java/lang/System.out:Ljava/io/PrintStream;
         9: iload_1       
        10: invokevirtual #25                 // Method java/io/PrintStream.println:(I)V
        13: return        
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      13     1     i   I
            0      13     0  args   [Ljava/lang/String;
    MethodParameters:
      Name                           Flags
      args

Solution

  • Looks like I have found the answer myself:

    Since i is a long, it needs two slots to be stored. However, it is still ok to put it in the LocalVariableTable once, as long as you count it twice when calculating the max locals.

    That means the code works if the bytecode looks like this (locals=3):

      public static void main(java.lang.String[]);
        descriptor: ([Ljava/lang/String;)V
        flags: ACC_PUBLIC, ACC_STATIC
        Code:
          stack=5, locals=3, args_size=1
             0: ldc2_w        #14                 // long 2l
             3: lstore_1      
             4: lload_1       
             5: ldc2_w        #14                 // long 2l
             8: lmul          
             9: lstore_1      
            10: getstatic     #21                 // Field java/lang/System.out:Ljava/io/PrintStream;
            13: lload_1       
            14: invokevirtual #27                 // Method java/io/PrintStream.println:(J)V
            17: return        
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0      17     1     i   J
                0      17     0  args   [Ljava/lang/String;
        MethodParameters:
          Name                           Flags
          args