2015-02-27 2 views
0

Я пытаюсь скомпилировать следующий код, используя пользовательский компилятор:JVM: Invalid индекс 1 в LocalVariableTable

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

в результате компиляции, при использовании javap, это 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 

Однако, когда я пытаюсь запустить Bytecode, JVM выбрасывает ClassFormatError, который читает Invalid index 1 in LocalVariableTable. Связано ли это с тем, что в LocalVariableTable слот 1 приходит перед слотом 0?

EDIT:

Если изменить переменную long на int, виртуальная машина не жалуется на все, даже если LocalVariableTable еще НЕСОРТИРОВАННАЯ:

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 

ответ

0

Похоже, я нашел ответ сам:

Поскольку i является long, она нуждается в два слота для хранения. Тем не менее, все равно нормально помещать его в LocalVariableTable один раз, если вы считаете его дважды при расчете максимальных локальных мест.

Это означает, что код работает, если байт-код выглядит следующим образом (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 
+0

'LocalVariableTable' предназначен только для отладки , вы можете опустить его, если он вам не нужен. Btw. если вам не нужен параметр 'args', вы также можете сохранить' long' в индекс '0', повторно используя место кадра стека. Тогда вам нужно всего 2 'locals' (а не то, что вам нужно * любую * локальную переменную в этом коде). Еще одно замечание: если вы хотите нажать 'long' constant' 2L', более эффективно использовать 'iconst_2', за которым следует' i2l', это занимает 2 байта, а 'ldc2_w' требует три байта * плюс * выделенный пул констант entry ... – Holger

+0

Более эффективный, чем в * более мелком байт-кодексе * или * более быстрое исполнение *? – Clashsoft

+0

Поскольку исполнение является специфичным для реализации/непредсказуемым, а JIT/оптимизаторы смогут обрабатывать одинаково, это имеет значение только размер байтового кода, но размер кода оказывает очевидное влияние на время загрузки/инициализации. – Holger

0

Это, вероятно, не ответ (не могу комментировать это:: P)

Ваш собственный компилятор где-то не так.

LocalVariableTable: 
    Start Length Slot Name Signature 
     0  17  1  i J 
     0  17  0 args [Ljava/lang/String; 

У вас не может быть одного и того же начального индекса для 2 локальных переменных.

Java компилятор дает вам:

Start Length Slot Name Signature 
    0  18  0 args [Ljava/lang/String; 
    4  14  1  i J 
+0

Если изменить '' long' в int' и не изменить сортировку на LVT, виртуальная машина Безразлично» t жалуются больше (см. мое Редактирование). – Clashsoft

+1

@Clashsoft - Я все еще вижу проблему с вашей локальной таблицей переменных. 2 переменные не могут начинаться с одного индекса: P – TheLostMind

+1

Да, они могут, потому что параметры всегда начинаются с индекса 0. – Clashsoft