3. Байт-код
Промежуточное
представление между Java и
машинным кодом
Исходный код переводится в
байт-код максимально
близко либо выражается его
средствами
Большинство ограничений
Java распространяются на
байт-код.
Source: http://viralpatel.net/blogs/java-virtual-machine-an-inside-story/
4. Что можно делать с байт-кодом?
Читать
– javap
– Анализ классов
– Анализ и модификация стороннего кода
Создавать
– Генерация классов на лету
– Компиляция
Изменять
– AOP
– Инструментация
– Профилирование
Понимать
– Франкенбилды
5. Почему он нужен редко?
Декомпиляторы
– Jad
Существующие средства AOP
– AspectJ
java.lang.reflect.Proxy
6. Средства для работы с байт-кодом
ASM
CGLIB
BCEL
SERP
Javassist
Jasmin
Jamaica
8. Структура класса
Все компилируется в .class
– Классы
– Интерфейсы
• <clinit>
– Аннотации
• java.lang.annotation.Annotation
– Перечисления
• java.lang.Enum
Source: http://viralpatel.net/blogs/tutorial-java-class-file-format-revealed/
9. Стек и регистры
Регистры используются для локальных переменных
Операции производятся со стеком, например:
– public float sum(int a, int b) { return a + b; } становится
• iload_1 // положить в стек значение параметра a
• iload_2 // положить в стек значение параметра b
• Iadd // сложить два верхних элемента стека, результат в стек
• I2f // сконвертировать верхний элемент стека из int в float
• freturn // вернуть верхний элемент стека
В стеке и регистрах хранятся 32-битные значения
long и double занимают две ячейки
10. Сигнатуры
Z = boolean, C, B, S, I, J = long, F, D
Массив: [[Z = boolean[][]
Объект: Ljava/lang/Integer; = java.lang.Integer
Метод: (II)V = void(int, int)
Пример использования:
– private Object x = new StringBuffer(); становится
• aload_0
• invokespecial java/lang/Object."<init>":()V
• aload_0
• new java/lang/StringBuffer
• dup
• invokespecial java/lang/StringBuffer."<init>":()V
• putfield x:Ljava/lang/Object;
• return
11. Опкоды
Соглашения
– Приставки
• b, c, s, i, l, f, d
• a = reference
– iload_0 = iload 0
Работа со стеком
– Занесение значения регистра в стек
• aload, dload, fload, iload, lload
– Перенос верхнего значения из стека в регистр
• astore, dstore, fstore, istore, lstore
– Запись константы в стек
• aconst_null, dconst_{0,1}, fconst_{0,1,2}, iconst_{m1,0,1,2,3,4,5}, lco
nst_{0,1}, ldc, ldc2, bipush, sipush
– Изменение вершины стека
• pop, pop2, dup, dup2, dup2_x1, dup2_x2, dup_x1, dup_x2, swap
12. Опкоды
Арифметические операции
– dadd, ddiv, dmul, dneg, drem, dsub, fadd, fdiv, fmul, fneg, frem, fs
ub, iadd, idiv, iinc, imul, ineg, irem, isub, ladd, ldiv, lmul, lneg, lre
m, lsub
Логические операции и операции сдвига
– iand, ior, ishl, ishr, iushr, ixor, land, lor, lshl, lshr, lushr, lxor
Приведение типа
– d2f, d2i, d2l, f2d, f2i, f2l, i2b, i2c, i2d, i2f, i2l, i2s, l2d, l2f, l2i
Безусловный переход
– goto, jsr, ret
Условный переход
– if_acmpeq, if_acmpne, if_icmpeq, if_icmpge, if_icmpgt, if_icmple,
if_icmplt, if_icmpne, ifeq, ifge, ifgt, ifle, iflt, ifne, ifnonnull, ifnull
13. Опкоды
Проверка условий
– dcmpg, dcmpl, fcmpg, fcmpl, lcmp, instanceof
Работа с массивами
– Создание и получение размера
• anewarray, arraylength, multianewarray, newarray
– Установка значения элемента
• aastore, bastore, castore, dastore, fastore, iastore, lastore, sastore
– Получение значения элемента
• aaload, baload, caload, daload, faload, iaload, laload, saload
Возврат значения и выбрасывание исключений
– areturn, dreturn, freturn, ireturn, lreturn, return, athrow
15. Методы и поля
Опкоды для вызова методов:
– invokedynamic
– invokeinterface
– invokespecial
– invokestatic
– Invokevirtual
Чтение и запись значений полей
– getfield, getstatic, putfield, putstatic
16. Сигнатуры
Всякое обращение к методу или полю содержит сигнатуру
Никакого встраивания
– Кроме static final полей с инициализатором
• public static int SIZE = 5;
• public static Object x = new Object();
• public static String NAME = “name”;
• public static String NAME; static {NAME = “name”;}
• interface IA { public String x = new Object().toString(); }
Метод или поле выбирается по имени и сигнатуре
Специальные методы <init> и <clinit>
17. Отладочная информация и исключения
Code: public void myMethod() {
0: iconst_0
1: istore_1
try {
2: goto 10 int x = 0;
5: astore_1 } catch (ArithmeticException e) {
6: aload_1 e.printStackTrace();
7: invokevirtual #23; //Method
java/lang/ArithmeticException.printStackTrace:()V }
10: return }
Exception table:
from to target type
0 2 5 Class java/lang/ArithmeticException
LineNumberTable:
line 32: 0
line 33: 5
line 34: 6
line 36: 10
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 this LMySample;
2 3 1 x I
6 4 1 e Ljava/lang/ArithmeticException;
18. Верификация
Проверка типов
Нет переполнения или опустошения стека
Нельзя перейти по неправильному адресу
Значение записывается в регистр перед чтением из него
Объект инициализируется перед его использованием
Вызовы методов и доступ к полям допустимы
20. Классы
Все становится классом
Внутренние классы, анонимные классы:
class MyOuterClass$MyInnerClass { private class MyInnerClass {
private int y; private int y;
private MyOuterClass this$0; public MyInnerClass(int y) {
public MyInnerClass(int y, MyOuterClass $parent) this.y = y;
{ }
this.y = y; }
this.this$0 = $parent;
} return new
static /*synthetic*/ int MyInnerClass(5).y;
access$0(MyOuterClass$MyInnerClass c) }
return c.y;
}
}
return MyOuterClass$MyInnerClass.access$0(new
MyOuterClass$MyInnerClass(5, this));
21. Инициализация
Инициализация полей переносится в конструктор /
статические конструктор, кроме примитивных и строковых
констант
private byte[] myArray = {1,2,3,4,5}
– byte[] x = new byte[5];
– x[0] = 1
– … x[4] = 5
– this.myArray = x;
У интерфейса может быть метод <clinit>, содержащий код
22. Средства Java в байт-коде
String s = x + “ “ + y;
– String s = new StringBuilder().append(x).append(“
“).append(y).toString();
Циклы можно записать при помощи условного перехода
Тернарый оператор записывается через if-else
synchronized(x) {…}
– Object $lock = x;
– monitorenter($lock);
– try {
– …; monitorexit($lock);
– } catch (Throwable t) {
– monitorexit($lock);
– throw t;
– }
30. Enum
Enums
– создается потомок java.lang.Enum
Compiled from "MyEnum.java"
public final class MyEnum extends java.lang.Enum{
public static final MyEnum A;
public static final MyEnum B;
public static final MyEnum C;
public static final MyEnum D;
private static final MyEnum[] ENUM$VALUES;
static {};
private MyEnum(java.lang.String, int);
public static MyEnum[] values();
public static MyEnum valueOf(java.lang.String);
}
31. Изменения в JDK 5
Varargs
– void myMethod(long a, int… b) -> void myMethod(long a, int[] b)
Autoboxing
– Добавляются вызовы методов
Annotations
– создается потомок java.lang.annotation.Annotation
– Аннотации добавлены в формат .class
– LOCAL_VARIABLE target
Compiled from "MyAnnotation.java"
public interface MyAnnotation extends java.lang.annotation.Annotation{
public abstract java.lang.String name();
public abstract int count();
}
32. Generics
public class GenericsTest<T, Z extends List<T>> {
public int myTest(Z z) {
return z.size();
}
}
public int myTest(java.util.List);
Code:
0: aload_1
1: invokeinterface #20, 1; //InterfaceMethod java/util/List.size:()I
6: ireturn
}
33. Generics
public final class GenericsTest2<T, Z extends ArrayList<T>> extends
GenericsTest<T, Z> {
public int myTest(Z z) {
return z.size() + 1;
}
}
public int myTest(java.util.ArrayList);
Code:
0: aload_1
1: invokevirtual #20; //Method java/util/ArrayList.size:()I
4: iconst_1
5: iadd
6: ireturn
public int myTest(java.util.List);
Code:
0: aload_0
1: aload_1
2: checkcast #21; //class java/util/ArrayList
5: invokevirtual #30; //Method myTest:(Ljava/util/ArrayList;)I
8: ireturn
}