Ассемблер Jasmin: инструкция «l2d», дающая java.lang.VerifyError: попытка разделить длинную или двойную часть стека

Я пишу компилятор для компиляции подмножества байт-кода Java в Java с использованием ассемблера Jasmin.

У меня проблемы с инструкцией 'l2d' (и родственными, но я думаю, что все они будут работать, как только я выясню, почему не работает эта).

Ссылка на инструкцию:

http://cs.au.dk/~mis/dOvs/jvmspec/ref-_l2d.html

Код, который я компилирую:

{
    double d = 10L;
}

По сути, я пытаюсь отразить способ, которым javac выполняет неявные преобразования типов между примитивными числовыми типами.

Выходной ассемблерный код Jasmin:

.source test3.jml
.class Test3
.super java/lang/Object
.method public static main([Ljava/lang/String;)V
    .limit stack 10
    .limit locals 100
    ldc2_w 10 ;Load constant numerical value 10
    l2d ;Convert left hand side to match the type of the right
    dstore 0 ;Store top of stack in 0 (d)
.end method

Важные строки, три перед .end method.

Текст после ';' является комментарием.

Точная ошибка, которую я получаю, когда пытаюсь запустить скомпилированный код:

Exception in thread "main" java.lang.VerifyError:(class: Test3, method: main signature: ([java/lang/String;)V) Attempt to split long or double on the stack
Could not find the main class: Test3. Program will exit.

Я думаю, это должно быть как-то связано с тем фактом, что long и double занимают 2 слота в стеке и 2 локальные переменные (объяснено здесь), но это все равно меня смущает.


person Will Sewell    schedule 24.11.2011    source источник
comment
Почему бы не скомпилировать его с помощью настоящего java-компилятора и не посмотреть, что он сгенерирует с помощью javap?   -  person James    schedule 25.11.2011
comment
Должно быть dstore_0, а не dstore 0, не так ли?   -  person Voo    schedule 25.11.2011
comment
Отличная идея. Я только что попробовал это сейчас. Проблема в том, что javac, кажется, много оптимизирует время компиляции; ему удается полностью избежать использования «l2d». По сути, он понимает, что то, что находится справа от «=», будет использоваться как двойное, поэтому он все время обрабатывает его как двойное. Даже когда я делаю что-то вроде 'double x = 10F + 12F + 10;', все выражение уже оценивается как '32D' во время компиляции. Оптимизация выходит за рамки моего проекта.   -  person Will Sewell    schedule 25.11.2011
comment
Воо, видимо и то и другое может быть. Из ссылки: 'dstore_‹n›' функционально эквивалентен 'dstore ‹n›', хотя обычно он более эффективен и также занимает меньше байтов в байт-коде. Я намерен изменить их из-за этого, но я сомневаюсь, что это вызывает эту проблему.   -  person Will Sewell    schedule 25.11.2011


Ответы (1)


Виртуальная машина Java использует локальные переменные для передачи параметров, поэтому в вашем коде локальная переменная с индексом 0 будет иметь тип String[]. Я недостаточно знаком с Jasmine, чтобы знать, нужно ли объявлять другие локальные переменные перед использованием, но можете ли вы просто попытаться сохранить двойную переменную в индексе 1?

person Jörn Horstmann    schedule 24.11.2011
comment
Интересно, хотя кажется, что Jasmin работает не совсем так, потому что я могу написать эквивалентный код для преобразования int в float, и он отлично работает, например. поплавок f = 10; Компилируется в: «ldc 10», затем «i2f», затем «fstore 0». И программа работает нормально. - person Will Sewell; 25.11.2011
comment
Это все еще может быть связано, поскольку ссылка на массив String использует только один слот стека, а для двойного требуется два. - person Jörn Horstmann; 25.11.2011