Примеры использования инструкции JVM Dup - PullRequest
0 голосов
/ 20 февраля 2019

Набор инструкций Java bytecode обеспечивает различные формы инструкции dup .У меня проблемы с пониманием того, как эти инструкции и инструкция swap могут быть полезны.Какой код Java будет производить байт-код с этими инструкциями при компиляции?

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Варианты dup могут появляться в обычном коде Java.

Например, как описано в в этом ответе , при создании объекта обычно используется dup, так как new Object() компилируется в

new #n              // n referencing Class java.lang.Object in the pool
dup
invokespecial #m    // m referencing Method java.lang.Object.<init>()V

Далее, intArray[expression]++ компилируется в

… (code pushing the results of intArray and expression)
dup2
iaload
iconst_1
iadd
iastore

и, немного любитель

public static long example3(Long[] array, int i, long l) {
    return array[i]=l;
}

компилируется в

   0: aload_0
   1: iload_1
   2: lload_2
   3: invokestatic  #3  // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
   6: dup_x2
   7: aastore
   8: invokevirtual #4  // Method java/lang/Long.longValue:()J
  11: lreturn

Изменение типа массива на long[] приводит к примеру dup2_x2

Как обсуждалось в , эти вопросы и ответы , javac никогда не используют swap или nop (в текущей реализации).Но только потому, что javac не использует конкретную инструкцию, вы не можете предполагать, что ни один компилятор не использует ее.

Например, есть другие компиляторы Java, такие как ECJ, но могут быть файлы классов, созданные другимиязыки программирования или уже являющиеся результатом инструментария инструмента, который становится актуальным, когда вы хотите инструмент код во время выполнения.И будущие версии javac также могут использовать инструкции, которые они не использовали ранее, так же как и до Java 8, код Java не использовал invokedynamic.

Это обсуждение указывает насценарий, где swap будет уместно.При использовании try-with-resource будет сгенерирован код, обрабатывающий исключение, перехваченное, в то время как уже есть перехваченное исключение.Current javac компилирует его (в основном) в

astore        n
aload         o
aload         n
invokevirtual #x // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V

, где o - старая переменная, содержащая уже перехваченное исключение, а n будет совершенно новой переменной, которая не понадобится при компиляциивместо этого

aload         o
swap
invokevirtual #x // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V

.Так что не похоже, чтобы эти инструкции никогда не были нужны экзотическим конструкциям.Это просто подробности реализации, когда конкретный генератор кода не использует их.

Говоря об инструментах, важно также помнить, что ClassFileTransformer не гарантирует получение точно такого же байт-кода, который создаетсякомпилятор.Это может быть эквивалентный байт-код.

Итак, суть в том, что если вы хотите реализовать ClassFileTransformer, вы должны быть готовы обработать каждый допустимый байт-код.

0 голосов
/ 21 февраля 2019

Я не знаю, когда javac его использует, но когда мы генерируем код, мы часто используем DUP и SWAP.Например, если вы делаете эквивалент

x.setCharm(y);
x.setSpin(z);

, тогда вы загрузите x и сразу же DUP его, потому что вызов первого метода приведет к удалению его из стека, и вы захотите использовать его дважды.

SWAP пригодится, когда вы делаете что-то вроде

y = x.getCharm();
z.setCharm(y);

, где первая инструкция оставляет y на вершине стека, затем вы складываете z и SWAP, так что теперь у вас есть правильные значенияв стеке для вызова второй инструкции.

...