SlideShare une entreprise Scribd logo
1  sur  186
Верификация Java байткода:
как, когда, а может
отключить?
Никита Липский
Excelsior LLC
2
OS+CPU
Monitoring
AOT
Bytecode
Classloading
engine
Bytecode Verification
Execution engine:
interpreter, JIT
Threading
Synchronization
Meta
information
Memory management,
Garbage Collection
Native methods
Анатомия JVM
3
Кто знает про себя ?
• Более 20 лет профессиональной карьеры
• Инициатор проекта Excelsior JET
– работал над проектом более 17 лет
– как идейный вдохновитель
– компиляторный инженер
– руководитель
– и много в каких еще ролях
• twitter: @pjBooms
4
Из доклада вы узнаете
1. Как и когда работает верификатор
2. Может ли верификатор байткода замедлить
исполнение программы и ее старт
3. Что бы было, если бы не было верификатора
4. Почему опасно его отключать
5. Как избежать VerifyError при порождении
байткода
5
Java class file & bytecode
6
Java class file
Класс файл Пример: Constant Pool
7
Версия
Constant Pool
Имя класса, модификаторы
Суперкласс, суперинтрфейсы
Поля
Методы
Атрибуты
CONSTANT_Integer: 100500
CONSTANT_Float: 3.1415
CONSTANT_String : Hello World!
CONSTANT_Class: java.lang.String
CONSTANT_FieldRef: A.field@int
CONSTANT_MethodRef: B.method(IJ)F
CONSTANT_InterfaceMethodRef: I.foo()V
Java class file
• Поля, методы тоже имеют атрибуты
(например, значения константных полей)
• Главный атрибут метода – это его код: Java
байт-код
8
Java bytecode
• Массив инструкций
• Стэк операндов инструкций метода
• Массив локальных переменных (аргументы
метода, локальные переменные)
9
Java bytecode
Инструкция берет свои операнды со стэка и кладет
результат на стэк. Пример:
10
0: iload 3
2: bipush 5
4: iadd
5: istore 4
7: …
#3
2:I _:?
#4
Java bytecode
Инструкция берет свои операнды со стэка и кладет
результат на стэк. Пример:
11
0: iload 3
2: bipush 5
4: iadd
5: istore 4
7: …
#3
2:I _:?
#4
2:I
Java bytecode
Инструкция берет свои операнды со стэка и кладет
результат на стэк. Пример:
12
0: iload 3
2: bipush 5
4: iadd
5: istore 4
7: …
#3
2:I _:?
#4
2:I
5:I
Java bytecode
Инструкция берет свои операнды со стэка и кладет
результат на стэк. Пример:
13
0: iload 3
2: bipush 5
4: iadd
5: istore 4
7: …
#3
2:I _:?
#4
7:I
Java bytecode
Инструкция берет свои операнды со стэка и кладет
результат на стэк. Пример:
14
0: iload 3
2: bipush 5
4: iadd
5: istore 4
7: …
#3
2:I 7:I
#4
C: StackOverflowError
A: Программа зациклится B: VerifyError
D: Не будет исполняться
Что произойдет при исполнении этого байт-кода?
Загрузка класс-файла.
Когда работает верификатор?
16
Стадии загрузки класса в JVM
• Загрузка (loading)
• Линковка (linking)
• Инициализация (initializing)
Глава “5. Loading, Linking, and Initializing”
спецификации JVM
Процесс загрузки класса
(создание класса)
• Читается class file
– Проверяется корректность формата (может
выбросить ClassFormatError)
• Создается ран-тайм представление класса в
выделенной области памяти
– runtime constant pool in Method Area aka Meta
Space aka Permanent Generation
• Грузятся суперкласс, суперинтерфейсы
18
Линковка
• Верификация байт-кода
• Подготовка
• Разрешение символьных ссылок
19
Разрешение символьных ссылок
A.java:
class A {
B useB;
int f1 = B.f;
int f2 = B.foo();
}
B.java:
class B {
static int f;
static int foo(){};
}
Разрешение символьных ссылок
21
A.class
…
CONSTANT_Class: B
CONSTANT_FieldRef: B.f@int
CONSTANT_MethodRef: B.foo()I
…
B.class
…
Field: f@int
Method: foo()I
…
Разрешение символьных ссылок
Класс может иметь ссылки на другие классы и поля,
методы других классов
• Ленивое разрешение
– ссылки разрешаются при первом доступе
• Энергичное разрешение
– разрешаются все ссылки какие возможно
22
Инициализация класса
23
class A {
static int i = 10;
static String s = "Hello";
static {
System.out.println(s);
}
}
A.class
…
<clinit>:
i = 10;
s = "Hello";
System.out.println(s);
…
Вызов статического инициализатора класса
Порядок стадий загрузки класса*
• Класс должен быть полностью загружен прежде,
чем слинкован
• Класс должен быть полностью проверифицирован
и подготовлен, прежде чем проинициализирован
• Ошибки разрешения ссылок, должны
происходить, когда ссылка реально требуется
* Глава 5.4 Спецификации JVM
Порядок стадий загрузки класса*
• Класс должен быть полностью загружен прежде,
чем слинкован
• Класс должен быть полностью проверифицирован
и подготовлен, прежде чем проинициализирован
• Ошибки разрешения ссылок, должны
происходить, когда ссылка реально требуется
* Глава 5.4 Спецификации JVM
Порядок стадий загрузки класса*
• Класс должен быть полностью загружен прежде,
чем слинкован
• Класс должен быть полностью проверифицирован
и подготовлен, прежде чем проинициализирован
• Ошибки разрешения ссылок, должны
происходить, когда ссылка реально требуется
* Глава 5.4 Спецификации JVM
Порядок стадий загрузки класса*
Вывод: верификация класса происходит до того как какой-либо
байткод какого-либо метода этого класса исполнится
Loading Verification Preparation Initializing
t
Resolution
Execution
Порядок стадий загрузки класса*
Вывод: верификация класса происходит до того как какой-либо
байткод какого-либо метода этого класса исполнится
Loading Verification Preparation Initializing
t
Resolution
Execution
C: StackOverflowError
A: Программа зациклится B: VerifyError
D: Не будет исполняться
Что произойдет при исполнении этого байт-кода?
Как?
• Картинка
30
Верификация Java байткода
Верификация Java байткода
Верификация Java байткода:
• проверка на статические ограничения (static constraints)
• проверка на структурные ограничения (structural
constraints)
32
Статические ограничения
• байткод не пуст и короче 65536 байт
• все инструкции идут одна за другой (нет “дыр”)
• все инструкции имеют известную JVM мнемонику (opcode)
• переходы внутри байткода не выходят за его пределы и
указывают на начало инструкции (не в середину)
• локальные переменные загружаются из корректных слотов
регистра локальных переменных (не выходят за его пределы)
• И т.д.
33
Статические ограничения
Проверяются за два прохода:
• Строится массив инструкций, каждая инструкция имеет
адрес (смещение внутри байткода)
• Проверяется, что все переходы корректны
На выходе получается управляющий граф (CFG) байткода
метода
34
Структурные ограничения
• Глубина стека в каждой инструкции должна быть
определенной величины для любого пути исполнения
35
Структурные ограничения
• Глубина стека в каждой инструкции должна быть
определенной величины для любого пути исполнения
• При исполнении любой инструкции не должна нарушится
типовая совместимость по присваиванию (assign
compatibility).
36
Структурные ограничения
• Глубина стека в каждой инструкции должна быть
определенной величины для любого пути исполнения
• При исполнении любой инструкции не должна нарушится
типовая совместимость по присваиванию (assign
compatibility).
– Пример: для инструкции putstatic C.f на вершине стэка должно
лежать значение, тип которого совместим по присваиванию с
типом поля C.f (для любого пути исполнения данной инструкции)
37
Структурные ограничения
Структурные ограничения оперируют термином “для любого
пути исполнения”. Однако верификация байткода должна
происходить до исполнения байткода.
Вопрос: Как это возможно?
Ответ: С помощью статического потокового анализа
38
Структурные ограничения
Структурные ограничения оперируют термином “для любого
пути исполнения”. Однако верификация байткода должна
происходить до исполнения байткода.
Вопрос: Как это возможно?
Ответ: С помощью статического потокового анализа
39
Статический потоковый анализ
40
Пример: вывод типов
val a = new T()
val b = a
41
new T()
a:?
b:?
Пример: вывод типов
val a = new T()
val b = a
42
new T()
a:?
b:?
Пример: вывод типов
val a = new T()
val b = a
43
new T()
a:T
b:?
Пример: вывод типов
val a = new T()
val b = a
44
new T()
a:T
b:T
Пример: проверка типов
val a = new T()
T2 b = a
45
new T()
a:?
b:T2
Пример: проверка типов
val a = new T()
T2 b = a
46
new T()
a:T
b:T2
Пример: проверка типов
val a = new T()
T2 b = a
47
new T()
a:T
b:T2
CHECK: T is assignable to T2
Пример: преобразование типов
val a = new T()
val b = (T2)a
48
new T()
(T2)
a
b:?
Пример: преобразование типов
val a = new T()
val b = (T2)a
49
new T()
(T2)
a
b:?
Пример: преобразование типов
val a = new T()
val b = (T2)a
50
new T()
(T2)
a
b:Т2
Пример: слияние типов
val a = cond?
new T1() :
new T2()
51
cond?
new
T1()
a:?
new T2()
Пример: слияние типов
val a = cond?
new T1() :
new T2()
52
cond?
new
T1()
a:?
new T2()
Пример: слияние типов
val a = cond?
new T1() :
new T2()
53
cond?
new
T1()
a:T1
new T2()
Пример: слияние типов
val a = cond?
new T1() :
new T2()
54
cond?
new
T1()
a:T1
new T2()
Пример: слияние типов
val a = cond?
new T1() :
new T2()
55
cond?
new
T1()
a:T1⋀T2
new T2()
Пример: условия, циклы
val a = null
val b = null
while (cond1) {
a = (cond2) ?
b :
new T1();
b = (cond3) ?
a :
new T2();
}
56
Статический потоковый анализ
Статический потоковый анализ имеет дело с:
57
Статический потоковый анализ
Статический потоковый анализ имеет дело с:
• Потоковым графом (управляющий граф программы)
58
Статический потоковый анализ
Статический потоковый анализ имеет дело с:
• Потоковым графом (управляющий граф программы)
• Пометками на вершинах (свойства, вычисляемые факты)
– Начальная разметка – известные факты в начале
59
Статический потоковый анализ
Статический потоковый анализ имеет дело с:
• Потоковым графом (управляющий граф программы)
• Пометками на вершинах (свойства, вычисляемые факты)
– Начальная разметка – известные факты в начале
• Свойства текут от вершины к вершине
60
Статический потоковый анализ
Статический потоковый анализ имеет дело с:
• Потоковым графом (управляющий граф программы)
• Пометками на вершинах (свойства, вычисляемые факты)
– Начальная разметка – известные факты в начале
• Свойства текут от вершины к вершине
• Свойства преобразуются на входе в вершину и сливаются
с уже имеющимися у вершины
61
62
Полурешетка свойств
Полурешетка – <L,⋀>:
x, y, z ∈ L
1. x ⋀ x = x (самоприменимость)
2. x ⋀ y = y ⋀ x (коммутативность)
3. x ⋀ (y ⋀ z) = (x ⋀ y) ⋀ z (ассоциативность)
Частичный порядок – ≤:
x ≤ y ⇔def x ⋀ y = x
x < y ⇔def x ⋀ y = x & x ≠ y
Пример: множества
A B
B < A
A BA⋀B
C:=A⋀B, C<A, C<B
Полурешетка свойств
Полурешетка свойств – это ограниченная решетка с
обрывающимися строго убывающими цепями:
1.  x1> x2 >… , k: ∄y ∈ L, xk > y
2. x, bx :  chain ∈ {x> x1 > …> xk}, |chain|< bx (ограниченность),
BL := max {bx} – высота полурешетки
3. ∈ L:  ⋀ x = , x∈ L (нуль, “дно”)
4. ⊤∈ L: ⊤ ⋀ x =x, x∈ L (единица, "штопор")
Примеры полурешеток
• Множества
• Полурешетка (!) иерархии классов
⋀ := LCA (lowest common ancestor)
Полурешетка иерархии классов
67

A F
B C G
D E
⊤
B extends AA B :=
 := j.l.Object
⊤ := null
B C⋀ = A
D E⋀ = C
B E⋀ = A
Полурешетка иерархии классов
68

A F
B C G
D E
⊤
B extends AA B :=
 := j.l.Object
⊤ := null
B C⋀ = A
D E⋀ = C
B E⋀ = A
Полурешетка иерархии классов
69

A F
B C G
D E
⊤
B extends AA B :=
 := j.l.Object
⊤ := null
B C⋀ = A
D E⋀ = C
B E⋀ = A
Полурешетка иерархии классов
70

A F
B C G
D E
⊤
B extends AA B :=
 := j.l.Object
⊤ := null
B C⋀ = A
D E⋀ = C
B E⋀ = A
Полурешетка иерархии классов
71

A F
B C G
D E
⊤
B extends AA B :=
 := j.l.Object
⊤ := null
B C⋀ = A
D E⋀ = C
B E⋀ = A
Полурешетка иерархии классов
72

A F
B C G
D E
⊤
B extends AA B :=
 := j.l.Object
⊤ := null
B C⋀ = A
D E⋀ = C
B E⋀ = A
Полурешетка иерархии классов
73

A F
B C G
D E
⊤
B extends AA B :=
 := j.l.Object
⊤ := null
B C⋀ = A
D E⋀ = C
B E⋀ = A
Полурешетка иерархии классов
74

A F
B C G
D E
⊤
B extends AA B :=
 := j.l.Object
⊤ := null
B C⋀ = A
D E⋀ = C
B E⋀ = A
Потоковые функции
Пусть <L,⋀> - полурешетка свойств
f: L → L – монотонная функция:
x, y ∈ L, x ≤ y ⇒ f(x) ≤ f(y)
Свойство GKUW (Graham, Kam, Ullman, Wegman):
f – монотонная функция ⇔
x, y ∈ L: f(x⋀y) ≤ f(x)⋀f(y)
f – дистрибутивная функция ⇔def
x, y ∈ L: f(x⋀y) = f(x)⋀f(y)
Потоковые функции
Пусть <L,⋀> - полурешетка свойств
f: L → L – монотонная функция:
x, y ∈ L, x ≤ y ⇒ f(x) ≤ f(y)
Свойство GKUW (Graham, Kam, Ullman, Wegman):
f – монотонная функция ⇔
x, y ∈ L: f(x⋀y) ≤ f(x)⋀f(y)
f – дистрибутивная функция ⇔def
x, y ∈ L: f(x⋀y) = f(x)⋀f(y)
Потоковые функции
Пусть <L,⋀> - полурешетка свойств
f: L → L – монотонная функция:
x, y ∈ L, x ≤ y ⇒ f(x) ≤ f(y)
Свойство GKUW (Graham, Kam, Ullman, Wegman):
f – монотонная функция ⇔
x, y ∈ L: f(x⋀y) ≤ f(x)⋀f(y)
f – дистрибутивная функция ⇔def
x, y ∈ L: f(x⋀y) = f(x)⋀f(y)
Пример дистрибутивной функции
Операция преобразования типа (cast):
(Т)v
Дистрибутивная функция:
Cast(T, Tv) := T ⋀ Tv, где Tv := Type(v)
Cast(T, Tv1 ⋀ Tv2) == Cast(T, Tv1) ⋀ Cast(T, Tv2)
78
Пример дистрибутивной функции
Операция преобразования типа (cast):
(Т)v
Дистрибутивная функция:
Cast(T, Tv) := T < Tv ? Tv : T, где Tv := Type(v)
Cast(T, Tv1 ⋀ Tv2) == Cast(T, Tv1) ⋀ Cast(T, Tv2)
79
Пример дистрибутивной функции
Операция преобразования типа (cast):
(Т)v
Дистрибутивная функция:
Cast(T, Tv) := T < Tv ? Tv : T, где Tv := Type(v)
Cast(T, Tv1 ⋀ Tv2) == Cast(T, Tv1) ⋀ Cast(T, Tv2)
80
Постановка задачи потокового анализа
DF=<G, Env, Init, PT> - задача потокового анализа:
G := <V, E, entry ∈V > - потоковый граф
Env := <L,⋀,F> - окружение потокового анализа
Init: V → L – начальная разметка
PT: V → F - преобразователи свойств
(для вершины v ∈ V будем записывать PTv)
Постановка задачи потокового анализа
( MOP решение)
DF = <G = <V, E>, Env = <L,⋀,F>, Init, PT> – задача
потокового анализа
Meet-over-all-paths (пересечение по всем путям) – (желаемое)
решение задачи потокового анализа
MOP(v) = ⋀p ∈Path(v) fp (⊤),
Path(v) = {p ∈ Paths(entry, v)| v∈V}
fp ⇔def fvn
∘… ∘ fv1
, p =(v1 .. vn) ∈ Paths(v1,vn)
fv ∈F ⇔def fv(l) = PTv(l) ⋀ Init(v), l ∈L
83
lv1
lv
PTv
PTv1
84
lv1
lv
PTv
PTv1
lv1
85
lv1
lv
PTv
PTv1
lv1
86
lv1
PTv(lv1
)⋀ lv
PTv
PTv1
87
lv1
l'v
PTv
PTv1
Приближенное решение
(стационарная разметка – MFP)
Правило разметки (ПР):
Пусть lv ∈ L – текущая пометка вершины v,
(v1 , v) ∈ E
l’v =def PTv(lv1
)⋀ lv – следующая пометка вершины v
Достижимая разметка :
M: V → L: получается из Init применением *(ПР)
Стационарная разметка (MFP):
Достижимая разметка не меняющаяся после любого применения ПР
lv1
PTv(lv1
)⋀ lv
PTv
PTv1
Свойства MFP
1. MFP DF = <G, Env, Init, PT> (сходимость)
2. !MFP DF = <G, Env, Init, PT> (единственность)
3. MFP(v) ≤ MOP(v), v∈V
(безопасность/корректность)
Свойства MFP
Теорема Килдалла
Let DF =<G, Env = <L,⋀,F> , Init, PT>:
f ∈ F ⇒ f – дистрибутивная(!), тогда:
MFP(v) = MOP(v), v∈V
(оптимальность)
Теорема о неразрешимости
Не существует алгоритма, который бы строил точное
решение (MOP) для любой задачи потокового анализа:
∄A . A вычисляет MOP
DF = <G, Env, Init, PT>
(неразрешимость)
Верификация байткода методом вывода
типов (type inference verifier)
Верификация байткода методом вывода типов
Type inference verifier – потоковый анализатор:
• Потоковый граф – управляющий граф (CFG)
• Решетка свойств – множество StackMapFrame
• Преобразователи свойств определены для каждой
инструкции байткода, согласно их семантики
93
Stack Map Frame
Stack Map Frame – свойство, вычисляемое для каждой
инструкции данного байткода метода:
• Stack: глубина и типы значений на стеке
94
Stack Map Frame
Stack Map Frame – свойство, вычисляемое для каждой
инструкции данного байткода метода:
• Stack: глубина и типы значений на стеке
• Locals: типы локальных переменных в регистре локальных
переменных
95
Пример
public static int add(int a, int b) { return a + b; }
96
0: iload 0
2: iload 1
4: iadd
5: ireturn
#0
int
#1
int
Пример
public static int add(int a, int b) { return a + b; }
97
0: iload 0
2: iload 1
4: iadd
5: ireturn
#0
int
#1
int
int
Пример
public static int add(int a, int b) { return a + b; }
98
0: iload 0
2: iload 1
4: iadd
5: ireturn
#0
int
#1
int
int
int
Пример
public static int add(int a, int b) { return a + b; }
99
0: iload 0
2: iload 1
4: iadd
5: ireturn
#0
int
#1
int
int
Пример
public static int add(int a, int b) { return a + b; }
100
0: iload 0
2: iload 1
4: iadd
5: ireturn
#0
int
#1
int
Пример 2
class A extends C{}; class B extends C{};
public C ifcond(boolean cond, A a, B b) {return cond?a:b;}
101
0: iload_0
1: ifeq 8
4: aload_1
5: goto 9
8: aload_2
9: areturn
#0
A
#1
int
#2
B
0
4
9
8
Пример 2
class A extends C{}; class B extends C{};
public C ifcond(boolean cond, A a, B b) {return cond?a:b;}
102
0: iload_0
1: ifeq 8
4: aload_1
5: goto 9
8: aload_2
9: areturn int
#0
A
#1
int
#2
B
0
4
9
8
Пример 2
class A extends C{}; class B extends C{};
public C ifcond(boolean cond, A a, B b) {return cond?a:b;}
103
0: iload_0
1: ifeq 8
4: aload_1
5: goto 9
8: aload_2
9: areturn
#0
A
#1
int
#2
B
0
4
9
8
Пример 2
class A extends C{}; class B extends C{};
public C ifcond(boolean cond, A a, B b) {return cond?a:b;}
104
0: iload_0
1: ifeq 8
4: aload_1
5: goto 9
8: aload_2
9: areturn A
#0
A
#1
int
#2
B
0
4
9
8
Пример 2
class A extends C{}; class B extends C{};
public C ifcond(boolean cond, A a, B b) {return cond?a:b;}
105
0: iload_0
1: ifeq 8
4: aload_1
5: goto 9
8: aload_2
9: areturn
#0
A
#1
int
#2
B
A
0
4
9
8
Пример 2
class A extends C{}; class B extends C{};
public C ifcond(boolean cond, A a, B b) {return cond?a:b;}
106
0: iload_0
1: ifeq 8
4: aload_1
5: goto 9
8: aload_2
9: areturn
#0
A
#1
int
#2
B
0
4
9
8
Пример 2
class A extends C{}; class B extends C{};
public C ifcond(boolean cond, A a, B b) {return cond?a:b;}
107
0: iload_0
1: ifeq 8
4: aload_1
5: goto 9
8: aload_2
9: areturn B
#0
A
#1
int
#2
B
0
4
9
8
Пример 2
class A extends C{}; class B extends C{};
public C ifcond(boolean cond, A a, B b) {return cond?a:b;}
108
0: iload_0
1: ifeq 8
4: aload_1
5: goto 9
8: aload_2
9: areturn B A⋀
#0
A
#1
int
#2
B
0
4
9
8
Пример 2
class A extends C{}; class B extends C{};
public C ifcond(boolean cond, A a, B b) {return cond?a:b;}
109
0: iload_0
1: ifeq 8
4: aload_1
5: goto 9
8: aload_2
9: areturn C
#0
A
#1
int
#2
B
0
4
9
8
Пример 3
110
SD: 0
SD: ?
SD: ?
SD: ?
SD: Stack Depth
Пример 3
111
SD: 0
SD: 1
SD: ?
SD: ?
SD: Stack Depth
Пример 3
112
SD: 0
SD: 1
SD: 2
SD: ?
SD: Stack Depth
Пример 3
113
SD: 0
SD: 1
SD: 2
SD: 1
SD: Stack Depth
Пример 3
114
SD: 0
SD: 1
SD: 2
SD: 1
SD: Stack Depth
Can’t merge
SD=1 with SD=0
Not verified!
Верификация байткода методом вывода типов
Каждая инструкция байткода определяет преобразователь
свойств:
F(opcode): StackMapFrame -> StackMapFrame
115
Верификация байткода методом вывода типов
Эти преобразователи дистрибутивны!
116
Верификация байткода методом вывода типов
Эти преобразователи дистрибутивны!
Значит верификатор строит точное решение задачи
верификации за конечное время без исполнения байткода!
117
Верификация байткода методом вывода типов
Эти преобразователи дистрибутивны!
Значит верификатор строит точное решение задачи
верификации за конечное время без исполнения байткода!
Но за какое время?
118
Оценка сложности алгоритма MFP
Утверждение:
Если обходить потоковый граф в глубину, то временная
сложность алгоритма MFP (AMFP):
T(AMFP) = O(BL*A*|V|),
Где A – количество обратных дуг в потоковом графе
A =O(|V|), на практике A ≤ 3
Верификация байткода методом вывода типов
Время работы верификатора зависит от:
• Количества инструкций
• Количества циклов
• Количества локальных переменных
• Максимальной глубины стека операндов
• Высоты иерархии классов
Дорого?
120
Верификация байткода методом вывода типов
Время работы верификатора зависит от:
• Количества инструкций
• Количества циклов
• Количества локальных переменных
• Максимальной глубины стека операндов
• Высоты иерархии классов
Дорого?
121
Верификация байткода методом
проверки типов (type checking verifier)
Верификация байткода методом
проверки типов
Вопрос: Как ускорить верификатор?
Идея: А что если мы знаем MFP решение
верификатора методом вывода типов?
Bingo! Тогда нам достаточно за один проход по байткоду
проверить, что неподвижная точка (MFP)
действительно неподвижная!
(не меняется при применении преобразователей свойств инструкций)
123
Верификация байткода методом
проверки типов
Вопрос: Как ускорить верификатор?
Идея: А что если мы знаем MFP решение
верификатора методом вывода типов?
Bingo! Тогда нам достаточно за один проход по байткоду
проверить, что неподвижная точка (MFP)
действительно неподвижная!
(не меняется при применении преобразователей свойств инструкций)
124
Верификация байткода методом
проверки типов
Вопрос: Как ускорить верификатор?
Идея: А что если мы знаем MFP решение
верификатора методом вывода типов?
Bingo! Тогда нам достаточно за один проход по байткоду
проверить, что неподвижная точка (MFP)
действительно неподвижная!
(не меняется при применении преобразователей свойств инструкций)
125
Верификация байткода методом
проверки типов
Split Verifier aka Type checking verifier:
• У байткода версии Java 5 может быть атрибут
StackMapTable (с Java 7 обязан быть)
126
Верификация байткода методом
проверки типов
Split Verifier aka Type checking verifier:
• У байткода версии Java 5 может быть атрибут
StackMapTable (с Java 7 обязан быть)
• StackMapTable – это список StackMapFrame
127
Верификация байткода методом
проверки типов
Split Verifier aka Type checking verifier:
• У байткода версии Java 5 может быть атрибут
StackMapTable (с Java 7 обязан быть)
• StackMapTable – это список StackMapFrame
• StackMapFrame есть для каждой начальной инструкции
линейных участков байткода, кроме первого
128
Верификация байткода методом
проверки типов
Split aka Type checking verifier за один проход по байткоду:
• вычисляет недостающие StackMapFrame: для каждой
инструкции проверяет входящие типы, вычисляет
исходящие (переносит ниже)
• проверяет что StackMapFrame из StackMapTable атрибута
не меняются при переносе StackMapFrame из инструкций
выше (проверка неподвижности точки)
129
Верификация байткода методом
проверки типов
Split aka Type checking verifier за один проход по байткоду:
• вычисляет недостающие StackMapFrame: для каждой
инструкции проверяет входящие типы, вычисляет
исходящие (переносит ниже)
• проверяет что StackMapFrame из StackMapTable атрибута
не меняются при переносе StackMapFrame из инструкций
выше (проверка неподвижности точки)
130
Роль верификатора байткода в JVM
Роль верификатора байткода в JVM
Вопросы:
1. Может ли верификатор байткода замедлить исполнение ?
2. Может ли верификатор байткода замедлить старт?
3. Что было бы, если бы не было верификатора байткода?
4. А что будет, если его отключить?
132
Роль верификатора байткода в JVM
Вопрос: Может ли верификатор байткода замедлить
исполнение?
А исполнение чего?
• Исполнение байткода метода
• Исполнение горячего кода программы
• Исполнение программы
133
Роль верификатора байткода в JVM
Вопрос: Может ли верификатор байткода замедлить
исполнение?
А исполнение чего?
• Исполнение байткода метода
• Исполнение горячего кода программы
• Исполнение программы
134
Роль верификатора байткода в JVM
Вопрос: Может ли верификатор байткода замедлить
исполнение?
А исполнение чего?
• Исполнение байткода метода
• Исполнение горячего кода программы
• Исполнение программы
135
Роль верификатора байткода в JVM
Вопрос: Может ли верификатор байткода замедлить
исполнение байткода метода?
Вспомним: Верификатор работает до исполнения!
Ответ: Нет!
136
Роль верификатора байткода в JVM
Вопрос: Может ли верификатор байткода замедлить
исполнение байткода метода?
Вспомним: Верификатор работает до исполнения байткода!
Ответ: Нет!
137
Роль верификатора байткода в JVM
Вопрос: Может ли верификатор байткода замедлить
исполнение байткода метода?
Вспомним: Верификатор работает до исполнения байткода!
Ответ: Нет!
138
Роль верификатора байткода в JVM
Вопрос: Может ли верификатор байткода замедлить
исполнение программы?
139
Роль верификатора байткода в JVM
Вопрос: Может ли верификатор байткода замедлить
исполнение программы?
Верификатор работает во время загрузки класса, загрузка
классов работает во время исполнения программы
140
Роль верификатора байткода в JVM
Вопрос: Может ли верификатор байткода замедлить
исполнение программы?
Верификатор работает во время загрузки класса, загрузка
классов работает во время исполнения программы
Ответ: вообще говоря, да
141
Роль верификатора байткода в JVM
Вопрос: Может ли верификатор байткода замедлить
исполнение горячего кода?
142
Роль верификатора байткода в JVM
Вопрос: Может ли верификатор байткода замедлить
исполнение горячего кода?
Во время исполнения горячего кода, все классы, с которым
он работает, были загружены пока код был холодным.
143
Роль верификатора байткода в JVM
Вопрос: Может ли верификатор байткода замедлить
исполнение горячего кода?
Во время исполнения горячего кода, все классы, с которым
он работает, были загружены пока код был холодным.
Ответ: нет
144
Роль верификатора байткода в JVM
Вопрос: Может ли верификатор байткода замедлить старт
программы?
145
Верификатор и время старта
0
2
4
6
8
10
12
14
16
18
20
Eclipse 4.6 Cold Start Eclipse 4.6 Warm Start
verify on
verify:none
146
Время старта Eclipse 4.6 в секундах
Верификатор и время старта
0
10
20
30
40
50
60
70
80
90
IntellIj IDEA 2016.3 Cold Start IntellIj IDEA 2016.3 Warm Start
verify on
verify:none
147
Время старта Intellij IDEA 2016.3 в секундах
Роль верификатора байткода в JVM
Вопрос: Может ли верификатор байткода замедлить старт
программы?
148
Роль верификатора байткода в JVM
Вопрос: Может ли верификатор байткода замедлить старт
программы?
Ответ: незначительно
149
Роль верификатора байткода в JVM
Вопрос: Может ли верификатор байткода замедлить старт
программы?
Ответ: незначительно
У JVM c AOT компилятором верификация на старте может не
происходить
150
Роль верификатора байткода в JVM
Вопрос: Что было бы, если бы не было верификатора?
151
Роль верификатора байткода в JVM
Вопрос: Что было бы, если бы не было верификатора?
Ответ: пришлось бы вставлять проверки во время исполнения:
152
Роль верификатора байткода в JVM
Вопрос: Что было бы, если бы не было верификатора?
Ответ: пришлось бы вставлять проверки во время исполнения:
• для инструкций работающих со стеком, проверять что стек
не пуст и не переполнится
153
Роль верификатора байткода в JVM
Вопрос: Что было бы, если бы не было верификатора?
Ответ: пришлось бы вставлять проверки во время исполнения:
• для инструкций работающих со стеком, проверять что стек
не пуст и не переполнится
• для того, чтобы сложить два числа проверять, что на стеке
лежат два числа
154
Роль верификатора байткода в JVM
Вопрос: Что было бы, если бы не было верификатора?
Ответ: пришлось бы вставлять проверки во время исполнения:
• для инструкций работающих со стеком, проверять что стек
не пуст и не переполнится
• для того, чтобы сложить два числа проверять, что на стеке
лежат два числа
Как бы быстро тогда работали Java программы?
155
Роль верификатора байткода в JVM
Факт: Интерпретатор не проверяет выходы за пределы стека
операндов и типовую совместимость: если надо сложить два
числа, он просто берет их со стека и складывает.
156
Роль верификатора байткода в JVM
Факт: Интерпретатор не проверяет выходы за пределы стека
операндов и типовую совместимость: если надо сложить два
числа, он просто берет их со стека и складывает.
Факт: JIT компилятор при генерации машинного кода тоже не
вставляет такие проверки в машинный код.
157
Роль верификатора байткода в JVM
Факт: Интерпретатор не проверяет выходы за пределы стека
операндов и типовую совместимость: если надо сложить два
числа, он просто берет их со стека и складывает.
Факт: JIT компилятор при генерации машинного кода тоже не
вставляет такие проверки в машинный код.
Вывод: Наличие верификатора – первопричина почему JVM
исполняет Java программы быстро!
158
Роль верификатора байткода в JVM
Вопрос: А что будет, если верификатор отключить?
# A fatal error has been detected by the Java Runtime Environment:
Exception in thread "main" java.lang.StackOverflowError
at test.foo(test.j)
at test.main(test.j:3)
#
# Internal Error (javaCalls.cpp:53), pid=8012, tid=16396
# guarantee(!thread->is_Compiler_thread()) failed: cannot make java calls
from the compiler
#
159
Роль верификатора байткода в JVM
Вопрос: А что будет, если верификатор отключить?
# A fatal error has been detected by the Java Runtime Environment:
Exception in thread "main" java.lang.StackOverflowError
at test.foo(test.j)
at test.main(test.j:3)
#
# Internal Error (javaCalls.cpp:53), pid=8012, tid=16396
# guarantee(!thread->is_Compiler_thread()) failed: cannot make java calls
from the compiler
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
160
Роль верификатора байткода в JVM
Вопрос: А что будет, если верификатор отключить?
Ответ: Отключение верификатора может приводить к
развалам JVM, что в свою очередь открывает
потенциальные дыры в безопасности.
161
Роль верификатора байткода в JVM
Вопрос: А что будет, если верификатор отключить?
Ответ: Отключение верификатора может приводить к
развалам JVM, что в свою очередь открывает
потенциальные дыры в безопасности.
Вывод: Наличие верификатора делает исполнение байткода
не только эффективным, но и безопасным!
162
Верификатор и библиотеки генерации
байткода
Библиотеки генерации байткода
• Низкоуровневые
– ASM
– BCEL
• Высокоуровневые
– Javassist
– cglib
– ByteBuddy
164
ASM библиотека
ASM библиотека
• Позволяет полностью контролировать содержимое
выходных классов, байткода
165
ASM библиотека
ASM библиотека
• Позволяет полностью контролировать содержимое
выходных классов, байткода
• Как следствие низкоуровневая: вы работаете
непосредственно с инструкциями байткода
166
ASM библиотека
ASM: пример кода
MethodVisitor methodVisitor = … ;
methodVisitor.visitVarInsn(Opcodes.ILOAD, 3);
methodVisitor.visitIntInsn (Opcodes.BIPUSH, 5);
methodVisitor.visitInsn (Opcodes.IADD);
methodVisitor.visitVarInsn(Opcodes.ISTORE, 4);
167
ASM библиотека
• Нужно знать семантику байткодных инструкций
• Легко породить неверифицируемый байткод
• ASM умеет вычислять StackMapTable атрибут
– с помощью того же потокового анализа
• Можно задавать StackMapTable атрибут руками
– для скорости; автоматическое вычисление замедляет ASM в 2 р.
168
ASM библиотека
• Нужно знать семантику байткодных инструкций
• Легко породить неверифицируемый байткод
• ASM умеет вычислять StackMapTable атрибут
– с помощью того же потокового анализа
• Можно задавать StackMapTable атрибут руками
– для скорости; автоматическое вычисление замедляет ASM в 2 р.
169
ASM библиотека
• Нужно знать семантику байткодных инструкций
• Легко породить неверифицируемый байткод
• ASM умеет вычислять StackMapTable атрибут
– с помощью того же потокового анализа
• Можно задавать StackMapTable атрибут руками
– для скорости; автоматическое вычисление замедляет ASM в 2 р.
170
ASM библиотека
• Нужно знать семантику байткодных инструкций
• Легко породить неверифицируемый байткод
• ASM умеет вычислять StackMapTable атрибут
– с помощью того же потокового анализа
• Можно задавать StackMapTable атрибут руками
– для скорости; автоматическое вычисление замедляет ASM в 2
раза
171
Библиотеки генерации байткода
Проблема: некоторые (старые) библиотеки,
манипулирующие байткодом, не умеют вычислять
StackMapFramе
172
Библиотеки генерации байткода
Проблема: некоторые (старые) библиотеки,
манипулирующие байткодом, не умеют вычислять
StackMapFramе
В результате вы можете получить ошибку:
java.lang.VerifyError: Expecting a stackmap frame at branch
173
Библиотеки генерации байткода
Проблема: некоторые (старые) библиотеки,
манипулирующие байткодом, не умеют вычислять
StackMapFramе
Можно отключить Typе Checking Verifier: -XX:-UseSplitVerifier
174
Библиотеки генерации байткода
Проблема: некоторые (старые) библиотеки,
манипулирующие байткодом, не умеют вычислять
StackMapFramе
Можно отключить Typе Checking Verifier: -XX:-UseSplitVerifier
Тогда будет работать Type Inference Verifier
175
Библиотеки генерации байткода
Проблема: некоторые (старые) библиотеки,
манипулирующие байткодом, не умеют вычислять
StackMapFramе
Можно отключить Typе Checking Verifier: -XX:-UseSplitVerifier
Тогда будет работать Type Inference Verifier
– Развал JVM не случится
176
Библиотеки генерации байткода
Проблема: некоторые (старые) библиотеки,
манипулирующие байткодом, не умеет вычислять
StackMapFramе
Можно отключить Typе Checking Verifier: -XX:-UseSplitVerifier
Тогда будет работать Type Inference Verifier
– Но старый верификатор не знает про invokedynamic
– Случится VerifyError при использовании лямбд
177
Библиотеки генерации байткода
Проблема: некоторые (старые) библиотеки,
манипулирующие байткодом, не умеет вычислять
StackMapFramе
Решение: не использовать старые библиотеки.
Используя ASM, вычислять StackMapFramе самим или с
помощью ASM.
178
Пример
179
Заключение
Верификатор Java байткода:
• Незаслуженно обделенная вниманием часть JVM
• Первопричина почему JVM исполняет программы быстро
(практически на уровне низкоуровневых языков)
• Гарантирует безопасность исполнения
• Отключать верификатор не имеет никакого практического
cмысла
• Зная как работает верификатор, порождать байткод легко
180
Заключение
Верификатор Java байткода:
• Незаслуженно обделенная вниманием часть JVM
• Первопричина почему JVM исполняет программы быстро
(практически на уровне низкоуровневых языков)
• Гарантирует безопасность исполнения
• Отключать верификатор не имеет никакого практического
cмысла
• Зная как работает верификатор, порождать байткод легко
181
Заключение
Верификатор Java байткода:
• Незаслуженно обделенная вниманием часть JVM
• Первопричина почему JVM исполняет программы быстро
(практически на уровне низкоуровневых языков)
• Гарантирует безопасность исполнения
• Отключать верификатор не имеет никакого практического
cмысла
• Зная как работает верификатор, порождать байткод легко
182
Заключение
Верификатор Java байткода:
• Незаслуженно обделенная вниманием часть JVM
• Первопричина почему JVM исполняет программы быстро
(практически на уровне низкоуровневых языков)
• Гарантирует безопасность исполнения
• Отключать верификатор не имеет никакого практического
cмысла
• Зная как работает верификатор, порождать байткод легко
183
Заключение
Верификатор Java байткода:
• Незаслуженно обделенная вниманием часть JVM
• Первопричина почему JVM исполняет программы быстро
(практически на уровне низкоуровневых языков)
• Гарантирует безопасность исполнения
• Отключать верификатор не имеет никакого практического
cмысла
• Зная как работает верификатор, порождать байткод легко
184
Заключение
Верификатор Java байткода:
• Незаслуженно обделенная вниманием часть JVM
• Первопричина почему JVM исполняет программы быстро
(практически на уровне низкоуровневых языков)
• Гарантирует безопасность исполнения
• Отключать верификатор не имеет никакого практического
cмысла
• Зная как работает верификатор, порождать байткод легко
185
Вопросы и ответы
Никита Липский,
Excelsior
nlipsky@excelsior-usa.com
twitter: @pjBooms 186

Contenu connexe

Tendances

Клиентская Java вне браузера. Делаем нативные клиенты на Java
Клиентская Java вне браузера. Делаем нативные клиенты на JavaКлиентская Java вне браузера. Делаем нативные клиенты на Java
Клиентская Java вне браузера. Делаем нативные клиенты на JavaNikita Lipsky
 
Асинхронность и сопрограммы
Асинхронность и сопрограммыАсинхронность и сопрограммы
Асинхронность и сопрограммыPlatonov Sergey
 
Java 9 модули
Java 9 модулиJava 9 модули
Java 9 модулиZheka Kozlov
 
Статический анализ кода: борьба с удорожанием ошибок
Статический анализ кода: борьба с удорожанием ошибокСтатический анализ кода: борьба с удорожанием ошибок
Статический анализ кода: борьба с удорожанием ошибокAndrey Karpov
 
Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)Victor_Cr
 
"Invokedynamic: роскошь или необходимость?"@ JavaOne Moscow 2013
"Invokedynamic: роскошь или необходимость?"@ JavaOne Moscow 2013"Invokedynamic: роскошь или необходимость?"@ JavaOne Moscow 2013
"Invokedynamic: роскошь или необходимость?"@ JavaOne Moscow 2013Vladimir Ivanov
 
Tech Talks @NSU: AOT-компиляция Java
Tech Talks @NSU: AOT-компиляция JavaTech Talks @NSU: AOT-компиляция Java
Tech Talks @NSU: AOT-компиляция JavaTech Talks @NSU
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаSergey Platonov
 
Scala performance под капотом
Scala performance под капотомScala performance под капотом
Scala performance под капотомRoman Grebennikov
 
03 - Java. Объекты, классы и пакеты в Java
03 - Java. Объекты, классы и пакеты в Java03 - Java. Объекты, классы и пакеты в Java
03 - Java. Объекты, классы и пакеты в JavaRoman Brovko
 
Исключения C++ через призму компиляторных оптимизаций. Роман Русяев ➠ CoreHa...
Исключения C++ через призму компиляторных оптимизаций. Роман Русяев ➠  CoreHa...Исключения C++ через призму компиляторных оптимизаций. Роман Русяев ➠  CoreHa...
Исключения C++ через призму компиляторных оптимизаций. Роман Русяев ➠ CoreHa...corehard_by
 
Что могут статические анализаторы, чего не могут программисты и тестировщики
Что могут статические анализаторы, чего не могут программисты и тестировщикиЧто могут статические анализаторы, чего не могут программисты и тестировщики
Что могут статические анализаторы, чего не могут программисты и тестировщикиAndrey Karpov
 
C++ STL & Qt. Занятие 10.
C++ STL & Qt. Занятие 10.C++ STL & Qt. Занятие 10.
C++ STL & Qt. Занятие 10.Igor Shkulipa
 
01 - Java. Введение в Java
01 - Java. Введение в Java01 - Java. Введение в Java
01 - Java. Введение в JavaRoman Brovko
 
JIT-компиляция в виртуальной машине Java (HighLoad++ 2013)
JIT-компиляция в виртуальной машине Java (HighLoad++ 2013)JIT-компиляция в виртуальной машине Java (HighLoad++ 2013)
JIT-компиляция в виртуальной машине Java (HighLoad++ 2013)aragozin
 
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptСергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptSergey Platonov
 
Akka: как я перестал бояться и полюбил асинхронный код
Akka: как я перестал бояться и полюбил асинхронный кодAkka: как я перестал бояться и полюбил асинхронный код
Akka: как я перестал бояться и полюбил асинхронный кодRoman Grebennikov
 
09 - Java. Тестирование Java-программ
09 - Java. Тестирование Java-программ09 - Java. Тестирование Java-программ
09 - Java. Тестирование Java-программRoman Brovko
 
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на LinuxПавел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на LinuxPlatonov Sergey
 

Tendances (20)

Клиентская Java вне браузера. Делаем нативные клиенты на Java
Клиентская Java вне браузера. Делаем нативные клиенты на JavaКлиентская Java вне браузера. Делаем нативные клиенты на Java
Клиентская Java вне браузера. Делаем нативные клиенты на Java
 
Асинхронность и сопрограммы
Асинхронность и сопрограммыАсинхронность и сопрограммы
Асинхронность и сопрограммы
 
Java 9 модули
Java 9 модулиJava 9 модули
Java 9 модули
 
Статический анализ кода: борьба с удорожанием ошибок
Статический анализ кода: борьба с удорожанием ошибокСтатический анализ кода: борьба с удорожанием ошибок
Статический анализ кода: борьба с удорожанием ошибок
 
Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)
 
"Invokedynamic: роскошь или необходимость?"@ JavaOne Moscow 2013
"Invokedynamic: роскошь или необходимость?"@ JavaOne Moscow 2013"Invokedynamic: роскошь или необходимость?"@ JavaOne Moscow 2013
"Invokedynamic: роскошь или необходимость?"@ JavaOne Moscow 2013
 
Tech Talks @NSU: AOT-компиляция Java
Tech Talks @NSU: AOT-компиляция JavaTech Talks @NSU: AOT-компиляция Java
Tech Talks @NSU: AOT-компиляция Java
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладка
 
Scala performance под капотом
Scala performance под капотомScala performance под капотом
Scala performance под капотом
 
03 - Java. Объекты, классы и пакеты в Java
03 - Java. Объекты, классы и пакеты в Java03 - Java. Объекты, классы и пакеты в Java
03 - Java. Объекты, классы и пакеты в Java
 
Исключения C++ через призму компиляторных оптимизаций. Роман Русяев ➠ CoreHa...
Исключения C++ через призму компиляторных оптимизаций. Роман Русяев ➠  CoreHa...Исключения C++ через призму компиляторных оптимизаций. Роман Русяев ➠  CoreHa...
Исключения C++ через призму компиляторных оптимизаций. Роман Русяев ➠ CoreHa...
 
Что могут статические анализаторы, чего не могут программисты и тестировщики
Что могут статические анализаторы, чего не могут программисты и тестировщикиЧто могут статические анализаторы, чего не могут программисты и тестировщики
Что могут статические анализаторы, чего не могут программисты и тестировщики
 
C++ STL & Qt. Занятие 10.
C++ STL & Qt. Занятие 10.C++ STL & Qt. Занятие 10.
C++ STL & Qt. Занятие 10.
 
01 - Java. Введение в Java
01 - Java. Введение в Java01 - Java. Введение в Java
01 - Java. Введение в Java
 
JIT-компиляция в виртуальной машине Java (HighLoad++ 2013)
JIT-компиляция в виртуальной машине Java (HighLoad++ 2013)JIT-компиляция в виртуальной машине Java (HighLoad++ 2013)
JIT-компиляция в виртуальной машине Java (HighLoad++ 2013)
 
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptСергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
 
Akka: как я перестал бояться и полюбил асинхронный код
Akka: как я перестал бояться и полюбил асинхронный кодAkka: как я перестал бояться и полюбил асинхронный код
Akka: как я перестал бояться и полюбил асинхронный код
 
09 - Java. Тестирование Java-программ
09 - Java. Тестирование Java-программ09 - Java. Тестирование Java-программ
09 - Java. Тестирование Java-программ
 
New Android NDK & JNI
New Android NDK & JNINew Android NDK & JNI
New Android NDK & JNI
 
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на LinuxПавел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
 

Similaire à Верификация Java байткода: когда, как, а может отключить?

Java Ahead-Of-Time compilation
Java Ahead-Of-Time compilationJava Ahead-Of-Time compilation
Java Ahead-Of-Time compilationNikita Lipsky
 
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...Andrey Karpov
 
AOT-компиляция Java
AOT-компиляция JavaAOT-компиляция Java
AOT-компиляция JavaTech Talks @NSU
 
Современный статический анализ кода: что умеет он, чего не умели линтеры
Современный статический анализ кода: что умеет он, чего не умели линтерыСовременный статический анализ кода: что умеет он, чего не умели линтеры
Современный статический анализ кода: что умеет он, чего не умели линтерыcorehard_by
 
20100321 virtualization igotti_lecture08
20100321 virtualization igotti_lecture0820100321 virtualization igotti_lecture08
20100321 virtualization igotti_lecture08Computer Science Club
 
Система обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на GroovyСистема обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на GroovyRegn
 
Технологии анализа бинарного кода приложений: требования, проблемы, инструменты
Технологии анализа бинарного кода приложений: требования, проблемы, инструментыТехнологии анализа бинарного кода приложений: требования, проблемы, инструменты
Технологии анализа бинарного кода приложений: требования, проблемы, инструментыPositive Development User Group
 
Zero Downtime PHP Deployment with Envoyer And Forge
Zero Downtime PHP Deployment with Envoyer And ForgeZero Downtime PHP Deployment with Envoyer And Forge
Zero Downtime PHP Deployment with Envoyer And ForgeYehor Herasymchuk
 
Инструментация среды исполнения в арсенале тестировщика
Инструментация среды исполнения в арсенале тестировщикаИнструментация среды исполнения в арсенале тестировщика
Инструментация среды исполнения в арсенале тестировщикаSQALab
 
Как создать качественный статический анализатор
Как создать качественный статический анализаторКак создать качественный статический анализатор
Как создать качественный статический анализаторAndrey Karpov
 
SAST, CWE, SEI CERT и другие умные слова из мира информационной безопасности
SAST, CWE, SEI CERT и другие умные слова из мира информационной безопасностиSAST, CWE, SEI CERT и другие умные слова из мира информационной безопасности
SAST, CWE, SEI CERT и другие умные слова из мира информационной безопасностиAndrey Karpov
 
SAST и Application Security: как бороться с уязвимостями в коде
SAST и Application Security: как бороться с уязвимостями в кодеSAST и Application Security: как бороться с уязвимостями в коде
SAST и Application Security: как бороться с уязвимостями в кодеAndrey Karpov
 
Архитектура растущего проекта на примере ВКонтакте / Алексей Акулович (ВКонт...
 Архитектура растущего проекта на примере ВКонтакте / Алексей Акулович (ВКонт... Архитектура растущего проекта на примере ВКонтакте / Алексей Акулович (ВКонт...
Архитектура растущего проекта на примере ВКонтакте / Алексей Акулович (ВКонт...Ontico
 
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#Andrey Karpov
 
Formal verification of operating system kernels
Formal verification of operating system kernelsFormal verification of operating system kernels
Formal verification of operating system kernelsDenis Efremov
 
CodeFest 2012. Липский Н. — JIT vs. AOT. Единство и борьба динамического и ст...
CodeFest 2012. Липский Н. — JIT vs. AOT. Единство и борьба динамического и ст...CodeFest 2012. Липский Н. — JIT vs. AOT. Единство и борьба динамического и ст...
CodeFest 2012. Липский Н. — JIT vs. AOT. Единство и борьба динамического и ст...CodeFest
 
Приемы Сontinuous Integration при разработке приложений на Caché
Приемы Сontinuous Integration при разработке приложений на CachéПриемы Сontinuous Integration при разработке приложений на Caché
Приемы Сontinuous Integration при разработке приложений на CachéInterSystems CEE
 
Caché github continuous intergration
Caché github continuous intergrationCaché github continuous intergration
Caché github continuous intergrationInterSystems
 
Формальная верификация кода на языке Си
Формальная верификация кода на языке СиФормальная верификация кода на языке Си
Формальная верификация кода на языке СиPositive Development User Group
 
Formal verification of C code
Formal verification of C codeFormal verification of C code
Formal verification of C codeDenis Efremov
 

Similaire à Верификация Java байткода: когда, как, а может отключить? (20)

Java Ahead-Of-Time compilation
Java Ahead-Of-Time compilationJava Ahead-Of-Time compilation
Java Ahead-Of-Time compilation
 
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
 
AOT-компиляция Java
AOT-компиляция JavaAOT-компиляция Java
AOT-компиляция Java
 
Современный статический анализ кода: что умеет он, чего не умели линтеры
Современный статический анализ кода: что умеет он, чего не умели линтерыСовременный статический анализ кода: что умеет он, чего не умели линтеры
Современный статический анализ кода: что умеет он, чего не умели линтеры
 
20100321 virtualization igotti_lecture08
20100321 virtualization igotti_lecture0820100321 virtualization igotti_lecture08
20100321 virtualization igotti_lecture08
 
Система обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на GroovyСистема обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на Groovy
 
Технологии анализа бинарного кода приложений: требования, проблемы, инструменты
Технологии анализа бинарного кода приложений: требования, проблемы, инструментыТехнологии анализа бинарного кода приложений: требования, проблемы, инструменты
Технологии анализа бинарного кода приложений: требования, проблемы, инструменты
 
Zero Downtime PHP Deployment with Envoyer And Forge
Zero Downtime PHP Deployment with Envoyer And ForgeZero Downtime PHP Deployment with Envoyer And Forge
Zero Downtime PHP Deployment with Envoyer And Forge
 
Инструментация среды исполнения в арсенале тестировщика
Инструментация среды исполнения в арсенале тестировщикаИнструментация среды исполнения в арсенале тестировщика
Инструментация среды исполнения в арсенале тестировщика
 
Как создать качественный статический анализатор
Как создать качественный статический анализаторКак создать качественный статический анализатор
Как создать качественный статический анализатор
 
SAST, CWE, SEI CERT и другие умные слова из мира информационной безопасности
SAST, CWE, SEI CERT и другие умные слова из мира информационной безопасностиSAST, CWE, SEI CERT и другие умные слова из мира информационной безопасности
SAST, CWE, SEI CERT и другие умные слова из мира информационной безопасности
 
SAST и Application Security: как бороться с уязвимостями в коде
SAST и Application Security: как бороться с уязвимостями в кодеSAST и Application Security: как бороться с уязвимостями в коде
SAST и Application Security: как бороться с уязвимостями в коде
 
Архитектура растущего проекта на примере ВКонтакте / Алексей Акулович (ВКонт...
 Архитектура растущего проекта на примере ВКонтакте / Алексей Акулович (ВКонт... Архитектура растущего проекта на примере ВКонтакте / Алексей Акулович (ВКонт...
Архитектура растущего проекта на примере ВКонтакте / Алексей Акулович (ВКонт...
 
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
 
Formal verification of operating system kernels
Formal verification of operating system kernelsFormal verification of operating system kernels
Formal verification of operating system kernels
 
CodeFest 2012. Липский Н. — JIT vs. AOT. Единство и борьба динамического и ст...
CodeFest 2012. Липский Н. — JIT vs. AOT. Единство и борьба динамического и ст...CodeFest 2012. Липский Н. — JIT vs. AOT. Единство и борьба динамического и ст...
CodeFest 2012. Липский Н. — JIT vs. AOT. Единство и борьба динамического и ст...
 
Приемы Сontinuous Integration при разработке приложений на Caché
Приемы Сontinuous Integration при разработке приложений на CachéПриемы Сontinuous Integration при разработке приложений на Caché
Приемы Сontinuous Integration при разработке приложений на Caché
 
Caché github continuous intergration
Caché github continuous intergrationCaché github continuous intergration
Caché github continuous intergration
 
Формальная верификация кода на языке Си
Формальная верификация кода на языке СиФормальная верификация кода на языке Си
Формальная верификация кода на языке Си
 
Formal verification of C code
Formal verification of C codeFormal verification of C code
Formal verification of C code
 

Plus de Nikita Lipsky

Escaping The Jar hell with Jigsaw Layers
Escaping The Jar hell with Jigsaw LayersEscaping The Jar hell with Jigsaw Layers
Escaping The Jar hell with Jigsaw LayersNikita Lipsky
 
JIT Versus AOT: Unity And Conflict of Dynamic and Static Compilers (JavaOne 2...
JIT Versus AOT: Unity And Conflict of Dynamic and Static Compilers (JavaOne 2...JIT Versus AOT: Unity And Conflict of Dynamic and Static Compilers (JavaOne 2...
JIT Versus AOT: Unity And Conflict of Dynamic and Static Compilers (JavaOne 2...Nikita Lipsky
 
Java 9 Modules: The Duke Yet Lives That OSGi Shall Depose
Java 9 Modules: The Duke Yet Lives That OSGi Shall DeposeJava 9 Modules: The Duke Yet Lives That OSGi Shall Depose
Java 9 Modules: The Duke Yet Lives That OSGi Shall DeposeNikita Lipsky
 
JIT vs. AOT: Unity And Conflict of Dynamic and Static Compilers
JIT vs. AOT: Unity And Conflict of Dynamic and Static Compilers JIT vs. AOT: Unity And Conflict of Dynamic and Static Compilers
JIT vs. AOT: Unity And Conflict of Dynamic and Static Compilers Nikita Lipsky
 
Ahead-Of-Time Compilation of Java Applications
Ahead-Of-Time Compilation of Java ApplicationsAhead-Of-Time Compilation of Java Applications
Ahead-Of-Time Compilation of Java ApplicationsNikita Lipsky
 
Delivering Native User Experience In Client Side Java Applications
Delivering Native User Experience In Client Side Java ApplicationsDelivering Native User Experience In Client Side Java Applications
Delivering Native User Experience In Client Side Java ApplicationsNikita Lipsky
 
Java Restart with WebFX
Java Restart with WebFX Java Restart with WebFX
Java Restart with WebFX Nikita Lipsky
 
Excelsior JET в действии
Excelsior JET в действииExcelsior JET в действии
Excelsior JET в действииNikita Lipsky
 
Веб 3.0. Есть ли будущее у Java в RIA и Mobile?
Веб 3.0. Есть ли будущее у Java в RIA и Mobile?Веб 3.0. Есть ли будущее у Java в RIA и Mobile?
Веб 3.0. Есть ли будущее у Java в RIA и Mobile?Nikita Lipsky
 
Занимательные истории из жизни технической поддержки JVM
Занимательные истории из жизни технической поддержки JVMЗанимательные истории из жизни технической поддержки JVM
Занимательные истории из жизни технической поддержки JVMNikita Lipsky
 
Неумолимая близость десктопа, веба и мобайла
Неумолимая близость десктопа, веба и мобайлаНеумолимая близость десктопа, веба и мобайла
Неумолимая близость десктопа, веба и мобайлаNikita Lipsky
 
Java худеет. Спроси меня как.
Java худеет. Спроси меня как.Java худеет. Спроси меня как.
Java худеет. Спроси меня как.Nikita Lipsky
 
История одной JVM в картинках
История одной JVM в картинкахИстория одной JVM в картинках
История одной JVM в картинкахNikita Lipsky
 

Plus de Nikita Lipsky (13)

Escaping The Jar hell with Jigsaw Layers
Escaping The Jar hell with Jigsaw LayersEscaping The Jar hell with Jigsaw Layers
Escaping The Jar hell with Jigsaw Layers
 
JIT Versus AOT: Unity And Conflict of Dynamic and Static Compilers (JavaOne 2...
JIT Versus AOT: Unity And Conflict of Dynamic and Static Compilers (JavaOne 2...JIT Versus AOT: Unity And Conflict of Dynamic and Static Compilers (JavaOne 2...
JIT Versus AOT: Unity And Conflict of Dynamic and Static Compilers (JavaOne 2...
 
Java 9 Modules: The Duke Yet Lives That OSGi Shall Depose
Java 9 Modules: The Duke Yet Lives That OSGi Shall DeposeJava 9 Modules: The Duke Yet Lives That OSGi Shall Depose
Java 9 Modules: The Duke Yet Lives That OSGi Shall Depose
 
JIT vs. AOT: Unity And Conflict of Dynamic and Static Compilers
JIT vs. AOT: Unity And Conflict of Dynamic and Static Compilers JIT vs. AOT: Unity And Conflict of Dynamic and Static Compilers
JIT vs. AOT: Unity And Conflict of Dynamic and Static Compilers
 
Ahead-Of-Time Compilation of Java Applications
Ahead-Of-Time Compilation of Java ApplicationsAhead-Of-Time Compilation of Java Applications
Ahead-Of-Time Compilation of Java Applications
 
Delivering Native User Experience In Client Side Java Applications
Delivering Native User Experience In Client Side Java ApplicationsDelivering Native User Experience In Client Side Java Applications
Delivering Native User Experience In Client Side Java Applications
 
Java Restart with WebFX
Java Restart with WebFX Java Restart with WebFX
Java Restart with WebFX
 
Excelsior JET в действии
Excelsior JET в действииExcelsior JET в действии
Excelsior JET в действии
 
Веб 3.0. Есть ли будущее у Java в RIA и Mobile?
Веб 3.0. Есть ли будущее у Java в RIA и Mobile?Веб 3.0. Есть ли будущее у Java в RIA и Mobile?
Веб 3.0. Есть ли будущее у Java в RIA и Mobile?
 
Занимательные истории из жизни технической поддержки JVM
Занимательные истории из жизни технической поддержки JVMЗанимательные истории из жизни технической поддержки JVM
Занимательные истории из жизни технической поддержки JVM
 
Неумолимая близость десктопа, веба и мобайла
Неумолимая близость десктопа, веба и мобайлаНеумолимая близость десктопа, веба и мобайла
Неумолимая близость десктопа, веба и мобайла
 
Java худеет. Спроси меня как.
Java худеет. Спроси меня как.Java худеет. Спроси меня как.
Java худеет. Спроси меня как.
 
История одной JVM в картинках
История одной JVM в картинкахИстория одной JVM в картинках
История одной JVM в картинках
 

Верификация Java байткода: когда, как, а может отключить?

  • 1. Верификация Java байткода: как, когда, а может отключить? Никита Липский Excelsior LLC
  • 2. 2 OS+CPU Monitoring AOT Bytecode Classloading engine Bytecode Verification Execution engine: interpreter, JIT Threading Synchronization Meta information Memory management, Garbage Collection Native methods Анатомия JVM
  • 3. 3
  • 4. Кто знает про себя ? • Более 20 лет профессиональной карьеры • Инициатор проекта Excelsior JET – работал над проектом более 17 лет – как идейный вдохновитель – компиляторный инженер – руководитель – и много в каких еще ролях • twitter: @pjBooms 4
  • 5. Из доклада вы узнаете 1. Как и когда работает верификатор 2. Может ли верификатор байткода замедлить исполнение программы и ее старт 3. Что бы было, если бы не было верификатора 4. Почему опасно его отключать 5. Как избежать VerifyError при порождении байткода 5
  • 6. Java class file & bytecode 6
  • 7. Java class file Класс файл Пример: Constant Pool 7 Версия Constant Pool Имя класса, модификаторы Суперкласс, суперинтрфейсы Поля Методы Атрибуты CONSTANT_Integer: 100500 CONSTANT_Float: 3.1415 CONSTANT_String : Hello World! CONSTANT_Class: java.lang.String CONSTANT_FieldRef: A.field@int CONSTANT_MethodRef: B.method(IJ)F CONSTANT_InterfaceMethodRef: I.foo()V
  • 8. Java class file • Поля, методы тоже имеют атрибуты (например, значения константных полей) • Главный атрибут метода – это его код: Java байт-код 8
  • 9. Java bytecode • Массив инструкций • Стэк операндов инструкций метода • Массив локальных переменных (аргументы метода, локальные переменные) 9
  • 10. Java bytecode Инструкция берет свои операнды со стэка и кладет результат на стэк. Пример: 10 0: iload 3 2: bipush 5 4: iadd 5: istore 4 7: … #3 2:I _:? #4
  • 11. Java bytecode Инструкция берет свои операнды со стэка и кладет результат на стэк. Пример: 11 0: iload 3 2: bipush 5 4: iadd 5: istore 4 7: … #3 2:I _:? #4 2:I
  • 12. Java bytecode Инструкция берет свои операнды со стэка и кладет результат на стэк. Пример: 12 0: iload 3 2: bipush 5 4: iadd 5: istore 4 7: … #3 2:I _:? #4 2:I 5:I
  • 13. Java bytecode Инструкция берет свои операнды со стэка и кладет результат на стэк. Пример: 13 0: iload 3 2: bipush 5 4: iadd 5: istore 4 7: … #3 2:I _:? #4 7:I
  • 14. Java bytecode Инструкция берет свои операнды со стэка и кладет результат на стэк. Пример: 14 0: iload 3 2: bipush 5 4: iadd 5: istore 4 7: … #3 2:I 7:I #4
  • 15. C: StackOverflowError A: Программа зациклится B: VerifyError D: Не будет исполняться Что произойдет при исполнении этого байт-кода?
  • 17. Стадии загрузки класса в JVM • Загрузка (loading) • Линковка (linking) • Инициализация (initializing) Глава “5. Loading, Linking, and Initializing” спецификации JVM
  • 18. Процесс загрузки класса (создание класса) • Читается class file – Проверяется корректность формата (может выбросить ClassFormatError) • Создается ран-тайм представление класса в выделенной области памяти – runtime constant pool in Method Area aka Meta Space aka Permanent Generation • Грузятся суперкласс, суперинтерфейсы 18
  • 19. Линковка • Верификация байт-кода • Подготовка • Разрешение символьных ссылок 19
  • 20. Разрешение символьных ссылок A.java: class A { B useB; int f1 = B.f; int f2 = B.foo(); } B.java: class B { static int f; static int foo(){}; }
  • 21. Разрешение символьных ссылок 21 A.class … CONSTANT_Class: B CONSTANT_FieldRef: B.f@int CONSTANT_MethodRef: B.foo()I … B.class … Field: f@int Method: foo()I …
  • 22. Разрешение символьных ссылок Класс может иметь ссылки на другие классы и поля, методы других классов • Ленивое разрешение – ссылки разрешаются при первом доступе • Энергичное разрешение – разрешаются все ссылки какие возможно 22
  • 23. Инициализация класса 23 class A { static int i = 10; static String s = "Hello"; static { System.out.println(s); } } A.class … <clinit>: i = 10; s = "Hello"; System.out.println(s); … Вызов статического инициализатора класса
  • 24. Порядок стадий загрузки класса* • Класс должен быть полностью загружен прежде, чем слинкован • Класс должен быть полностью проверифицирован и подготовлен, прежде чем проинициализирован • Ошибки разрешения ссылок, должны происходить, когда ссылка реально требуется * Глава 5.4 Спецификации JVM
  • 25. Порядок стадий загрузки класса* • Класс должен быть полностью загружен прежде, чем слинкован • Класс должен быть полностью проверифицирован и подготовлен, прежде чем проинициализирован • Ошибки разрешения ссылок, должны происходить, когда ссылка реально требуется * Глава 5.4 Спецификации JVM
  • 26. Порядок стадий загрузки класса* • Класс должен быть полностью загружен прежде, чем слинкован • Класс должен быть полностью проверифицирован и подготовлен, прежде чем проинициализирован • Ошибки разрешения ссылок, должны происходить, когда ссылка реально требуется * Глава 5.4 Спецификации JVM
  • 27. Порядок стадий загрузки класса* Вывод: верификация класса происходит до того как какой-либо байткод какого-либо метода этого класса исполнится Loading Verification Preparation Initializing t Resolution Execution
  • 28. Порядок стадий загрузки класса* Вывод: верификация класса происходит до того как какой-либо байткод какого-либо метода этого класса исполнится Loading Verification Preparation Initializing t Resolution Execution
  • 29. C: StackOverflowError A: Программа зациклится B: VerifyError D: Не будет исполняться Что произойдет при исполнении этого байт-кода?
  • 32. Верификация Java байткода Верификация Java байткода: • проверка на статические ограничения (static constraints) • проверка на структурные ограничения (structural constraints) 32
  • 33. Статические ограничения • байткод не пуст и короче 65536 байт • все инструкции идут одна за другой (нет “дыр”) • все инструкции имеют известную JVM мнемонику (opcode) • переходы внутри байткода не выходят за его пределы и указывают на начало инструкции (не в середину) • локальные переменные загружаются из корректных слотов регистра локальных переменных (не выходят за его пределы) • И т.д. 33
  • 34. Статические ограничения Проверяются за два прохода: • Строится массив инструкций, каждая инструкция имеет адрес (смещение внутри байткода) • Проверяется, что все переходы корректны На выходе получается управляющий граф (CFG) байткода метода 34
  • 35. Структурные ограничения • Глубина стека в каждой инструкции должна быть определенной величины для любого пути исполнения 35
  • 36. Структурные ограничения • Глубина стека в каждой инструкции должна быть определенной величины для любого пути исполнения • При исполнении любой инструкции не должна нарушится типовая совместимость по присваиванию (assign compatibility). 36
  • 37. Структурные ограничения • Глубина стека в каждой инструкции должна быть определенной величины для любого пути исполнения • При исполнении любой инструкции не должна нарушится типовая совместимость по присваиванию (assign compatibility). – Пример: для инструкции putstatic C.f на вершине стэка должно лежать значение, тип которого совместим по присваиванию с типом поля C.f (для любого пути исполнения данной инструкции) 37
  • 38. Структурные ограничения Структурные ограничения оперируют термином “для любого пути исполнения”. Однако верификация байткода должна происходить до исполнения байткода. Вопрос: Как это возможно? Ответ: С помощью статического потокового анализа 38
  • 39. Структурные ограничения Структурные ограничения оперируют термином “для любого пути исполнения”. Однако верификация байткода должна происходить до исполнения байткода. Вопрос: Как это возможно? Ответ: С помощью статического потокового анализа 39
  • 41. Пример: вывод типов val a = new T() val b = a 41 new T() a:? b:?
  • 42. Пример: вывод типов val a = new T() val b = a 42 new T() a:? b:?
  • 43. Пример: вывод типов val a = new T() val b = a 43 new T() a:T b:?
  • 44. Пример: вывод типов val a = new T() val b = a 44 new T() a:T b:T
  • 45. Пример: проверка типов val a = new T() T2 b = a 45 new T() a:? b:T2
  • 46. Пример: проверка типов val a = new T() T2 b = a 46 new T() a:T b:T2
  • 47. Пример: проверка типов val a = new T() T2 b = a 47 new T() a:T b:T2 CHECK: T is assignable to T2
  • 48. Пример: преобразование типов val a = new T() val b = (T2)a 48 new T() (T2) a b:?
  • 49. Пример: преобразование типов val a = new T() val b = (T2)a 49 new T() (T2) a b:?
  • 50. Пример: преобразование типов val a = new T() val b = (T2)a 50 new T() (T2) a b:Т2
  • 51. Пример: слияние типов val a = cond? new T1() : new T2() 51 cond? new T1() a:? new T2()
  • 52. Пример: слияние типов val a = cond? new T1() : new T2() 52 cond? new T1() a:? new T2()
  • 53. Пример: слияние типов val a = cond? new T1() : new T2() 53 cond? new T1() a:T1 new T2()
  • 54. Пример: слияние типов val a = cond? new T1() : new T2() 54 cond? new T1() a:T1 new T2()
  • 55. Пример: слияние типов val a = cond? new T1() : new T2() 55 cond? new T1() a:T1⋀T2 new T2()
  • 56. Пример: условия, циклы val a = null val b = null while (cond1) { a = (cond2) ? b : new T1(); b = (cond3) ? a : new T2(); } 56
  • 57. Статический потоковый анализ Статический потоковый анализ имеет дело с: 57
  • 58. Статический потоковый анализ Статический потоковый анализ имеет дело с: • Потоковым графом (управляющий граф программы) 58
  • 59. Статический потоковый анализ Статический потоковый анализ имеет дело с: • Потоковым графом (управляющий граф программы) • Пометками на вершинах (свойства, вычисляемые факты) – Начальная разметка – известные факты в начале 59
  • 60. Статический потоковый анализ Статический потоковый анализ имеет дело с: • Потоковым графом (управляющий граф программы) • Пометками на вершинах (свойства, вычисляемые факты) – Начальная разметка – известные факты в начале • Свойства текут от вершины к вершине 60
  • 61. Статический потоковый анализ Статический потоковый анализ имеет дело с: • Потоковым графом (управляющий граф программы) • Пометками на вершинах (свойства, вычисляемые факты) – Начальная разметка – известные факты в начале • Свойства текут от вершины к вершине • Свойства преобразуются на входе в вершину и сливаются с уже имеющимися у вершины 61
  • 62. 62
  • 63. Полурешетка свойств Полурешетка – <L,⋀>: x, y, z ∈ L 1. x ⋀ x = x (самоприменимость) 2. x ⋀ y = y ⋀ x (коммутативность) 3. x ⋀ (y ⋀ z) = (x ⋀ y) ⋀ z (ассоциативность) Частичный порядок – ≤: x ≤ y ⇔def x ⋀ y = x x < y ⇔def x ⋀ y = x & x ≠ y
  • 64. Пример: множества A B B < A A BA⋀B C:=A⋀B, C<A, C<B
  • 65. Полурешетка свойств Полурешетка свойств – это ограниченная решетка с обрывающимися строго убывающими цепями: 1.  x1> x2 >… , k: ∄y ∈ L, xk > y 2. x, bx :  chain ∈ {x> x1 > …> xk}, |chain|< bx (ограниченность), BL := max {bx} – высота полурешетки 3. ∈ L:  ⋀ x = , x∈ L (нуль, “дно”) 4. ⊤∈ L: ⊤ ⋀ x =x, x∈ L (единица, "штопор")
  • 66. Примеры полурешеток • Множества • Полурешетка (!) иерархии классов ⋀ := LCA (lowest common ancestor)
  • 67. Полурешетка иерархии классов 67  A F B C G D E ⊤ B extends AA B :=  := j.l.Object ⊤ := null B C⋀ = A D E⋀ = C B E⋀ = A
  • 68. Полурешетка иерархии классов 68  A F B C G D E ⊤ B extends AA B :=  := j.l.Object ⊤ := null B C⋀ = A D E⋀ = C B E⋀ = A
  • 69. Полурешетка иерархии классов 69  A F B C G D E ⊤ B extends AA B :=  := j.l.Object ⊤ := null B C⋀ = A D E⋀ = C B E⋀ = A
  • 70. Полурешетка иерархии классов 70  A F B C G D E ⊤ B extends AA B :=  := j.l.Object ⊤ := null B C⋀ = A D E⋀ = C B E⋀ = A
  • 71. Полурешетка иерархии классов 71  A F B C G D E ⊤ B extends AA B :=  := j.l.Object ⊤ := null B C⋀ = A D E⋀ = C B E⋀ = A
  • 72. Полурешетка иерархии классов 72  A F B C G D E ⊤ B extends AA B :=  := j.l.Object ⊤ := null B C⋀ = A D E⋀ = C B E⋀ = A
  • 73. Полурешетка иерархии классов 73  A F B C G D E ⊤ B extends AA B :=  := j.l.Object ⊤ := null B C⋀ = A D E⋀ = C B E⋀ = A
  • 74. Полурешетка иерархии классов 74  A F B C G D E ⊤ B extends AA B :=  := j.l.Object ⊤ := null B C⋀ = A D E⋀ = C B E⋀ = A
  • 75. Потоковые функции Пусть <L,⋀> - полурешетка свойств f: L → L – монотонная функция: x, y ∈ L, x ≤ y ⇒ f(x) ≤ f(y) Свойство GKUW (Graham, Kam, Ullman, Wegman): f – монотонная функция ⇔ x, y ∈ L: f(x⋀y) ≤ f(x)⋀f(y) f – дистрибутивная функция ⇔def x, y ∈ L: f(x⋀y) = f(x)⋀f(y)
  • 76. Потоковые функции Пусть <L,⋀> - полурешетка свойств f: L → L – монотонная функция: x, y ∈ L, x ≤ y ⇒ f(x) ≤ f(y) Свойство GKUW (Graham, Kam, Ullman, Wegman): f – монотонная функция ⇔ x, y ∈ L: f(x⋀y) ≤ f(x)⋀f(y) f – дистрибутивная функция ⇔def x, y ∈ L: f(x⋀y) = f(x)⋀f(y)
  • 77. Потоковые функции Пусть <L,⋀> - полурешетка свойств f: L → L – монотонная функция: x, y ∈ L, x ≤ y ⇒ f(x) ≤ f(y) Свойство GKUW (Graham, Kam, Ullman, Wegman): f – монотонная функция ⇔ x, y ∈ L: f(x⋀y) ≤ f(x)⋀f(y) f – дистрибутивная функция ⇔def x, y ∈ L: f(x⋀y) = f(x)⋀f(y)
  • 78. Пример дистрибутивной функции Операция преобразования типа (cast): (Т)v Дистрибутивная функция: Cast(T, Tv) := T ⋀ Tv, где Tv := Type(v) Cast(T, Tv1 ⋀ Tv2) == Cast(T, Tv1) ⋀ Cast(T, Tv2) 78
  • 79. Пример дистрибутивной функции Операция преобразования типа (cast): (Т)v Дистрибутивная функция: Cast(T, Tv) := T < Tv ? Tv : T, где Tv := Type(v) Cast(T, Tv1 ⋀ Tv2) == Cast(T, Tv1) ⋀ Cast(T, Tv2) 79
  • 80. Пример дистрибутивной функции Операция преобразования типа (cast): (Т)v Дистрибутивная функция: Cast(T, Tv) := T < Tv ? Tv : T, где Tv := Type(v) Cast(T, Tv1 ⋀ Tv2) == Cast(T, Tv1) ⋀ Cast(T, Tv2) 80
  • 81. Постановка задачи потокового анализа DF=<G, Env, Init, PT> - задача потокового анализа: G := <V, E, entry ∈V > - потоковый граф Env := <L,⋀,F> - окружение потокового анализа Init: V → L – начальная разметка PT: V → F - преобразователи свойств (для вершины v ∈ V будем записывать PTv)
  • 82. Постановка задачи потокового анализа ( MOP решение) DF = <G = <V, E>, Env = <L,⋀,F>, Init, PT> – задача потокового анализа Meet-over-all-paths (пересечение по всем путям) – (желаемое) решение задачи потокового анализа MOP(v) = ⋀p ∈Path(v) fp (⊤), Path(v) = {p ∈ Paths(entry, v)| v∈V} fp ⇔def fvn ∘… ∘ fv1 , p =(v1 .. vn) ∈ Paths(v1,vn) fv ∈F ⇔def fv(l) = PTv(l) ⋀ Init(v), l ∈L
  • 88. Приближенное решение (стационарная разметка – MFP) Правило разметки (ПР): Пусть lv ∈ L – текущая пометка вершины v, (v1 , v) ∈ E l’v =def PTv(lv1 )⋀ lv – следующая пометка вершины v Достижимая разметка : M: V → L: получается из Init применением *(ПР) Стационарная разметка (MFP): Достижимая разметка не меняющаяся после любого применения ПР lv1 PTv(lv1 )⋀ lv PTv PTv1
  • 89. Свойства MFP 1. MFP DF = <G, Env, Init, PT> (сходимость) 2. !MFP DF = <G, Env, Init, PT> (единственность) 3. MFP(v) ≤ MOP(v), v∈V (безопасность/корректность)
  • 90. Свойства MFP Теорема Килдалла Let DF =<G, Env = <L,⋀,F> , Init, PT>: f ∈ F ⇒ f – дистрибутивная(!), тогда: MFP(v) = MOP(v), v∈V (оптимальность)
  • 91. Теорема о неразрешимости Не существует алгоритма, который бы строил точное решение (MOP) для любой задачи потокового анализа: ∄A . A вычисляет MOP DF = <G, Env, Init, PT> (неразрешимость)
  • 92. Верификация байткода методом вывода типов (type inference verifier)
  • 93. Верификация байткода методом вывода типов Type inference verifier – потоковый анализатор: • Потоковый граф – управляющий граф (CFG) • Решетка свойств – множество StackMapFrame • Преобразователи свойств определены для каждой инструкции байткода, согласно их семантики 93
  • 94. Stack Map Frame Stack Map Frame – свойство, вычисляемое для каждой инструкции данного байткода метода: • Stack: глубина и типы значений на стеке 94
  • 95. Stack Map Frame Stack Map Frame – свойство, вычисляемое для каждой инструкции данного байткода метода: • Stack: глубина и типы значений на стеке • Locals: типы локальных переменных в регистре локальных переменных 95
  • 96. Пример public static int add(int a, int b) { return a + b; } 96 0: iload 0 2: iload 1 4: iadd 5: ireturn #0 int #1 int
  • 97. Пример public static int add(int a, int b) { return a + b; } 97 0: iload 0 2: iload 1 4: iadd 5: ireturn #0 int #1 int int
  • 98. Пример public static int add(int a, int b) { return a + b; } 98 0: iload 0 2: iload 1 4: iadd 5: ireturn #0 int #1 int int int
  • 99. Пример public static int add(int a, int b) { return a + b; } 99 0: iload 0 2: iload 1 4: iadd 5: ireturn #0 int #1 int int
  • 100. Пример public static int add(int a, int b) { return a + b; } 100 0: iload 0 2: iload 1 4: iadd 5: ireturn #0 int #1 int
  • 101. Пример 2 class A extends C{}; class B extends C{}; public C ifcond(boolean cond, A a, B b) {return cond?a:b;} 101 0: iload_0 1: ifeq 8 4: aload_1 5: goto 9 8: aload_2 9: areturn #0 A #1 int #2 B 0 4 9 8
  • 102. Пример 2 class A extends C{}; class B extends C{}; public C ifcond(boolean cond, A a, B b) {return cond?a:b;} 102 0: iload_0 1: ifeq 8 4: aload_1 5: goto 9 8: aload_2 9: areturn int #0 A #1 int #2 B 0 4 9 8
  • 103. Пример 2 class A extends C{}; class B extends C{}; public C ifcond(boolean cond, A a, B b) {return cond?a:b;} 103 0: iload_0 1: ifeq 8 4: aload_1 5: goto 9 8: aload_2 9: areturn #0 A #1 int #2 B 0 4 9 8
  • 104. Пример 2 class A extends C{}; class B extends C{}; public C ifcond(boolean cond, A a, B b) {return cond?a:b;} 104 0: iload_0 1: ifeq 8 4: aload_1 5: goto 9 8: aload_2 9: areturn A #0 A #1 int #2 B 0 4 9 8
  • 105. Пример 2 class A extends C{}; class B extends C{}; public C ifcond(boolean cond, A a, B b) {return cond?a:b;} 105 0: iload_0 1: ifeq 8 4: aload_1 5: goto 9 8: aload_2 9: areturn #0 A #1 int #2 B A 0 4 9 8
  • 106. Пример 2 class A extends C{}; class B extends C{}; public C ifcond(boolean cond, A a, B b) {return cond?a:b;} 106 0: iload_0 1: ifeq 8 4: aload_1 5: goto 9 8: aload_2 9: areturn #0 A #1 int #2 B 0 4 9 8
  • 107. Пример 2 class A extends C{}; class B extends C{}; public C ifcond(boolean cond, A a, B b) {return cond?a:b;} 107 0: iload_0 1: ifeq 8 4: aload_1 5: goto 9 8: aload_2 9: areturn B #0 A #1 int #2 B 0 4 9 8
  • 108. Пример 2 class A extends C{}; class B extends C{}; public C ifcond(boolean cond, A a, B b) {return cond?a:b;} 108 0: iload_0 1: ifeq 8 4: aload_1 5: goto 9 8: aload_2 9: areturn B A⋀ #0 A #1 int #2 B 0 4 9 8
  • 109. Пример 2 class A extends C{}; class B extends C{}; public C ifcond(boolean cond, A a, B b) {return cond?a:b;} 109 0: iload_0 1: ifeq 8 4: aload_1 5: goto 9 8: aload_2 9: areturn C #0 A #1 int #2 B 0 4 9 8
  • 110. Пример 3 110 SD: 0 SD: ? SD: ? SD: ? SD: Stack Depth
  • 111. Пример 3 111 SD: 0 SD: 1 SD: ? SD: ? SD: Stack Depth
  • 112. Пример 3 112 SD: 0 SD: 1 SD: 2 SD: ? SD: Stack Depth
  • 113. Пример 3 113 SD: 0 SD: 1 SD: 2 SD: 1 SD: Stack Depth
  • 114. Пример 3 114 SD: 0 SD: 1 SD: 2 SD: 1 SD: Stack Depth Can’t merge SD=1 with SD=0 Not verified!
  • 115. Верификация байткода методом вывода типов Каждая инструкция байткода определяет преобразователь свойств: F(opcode): StackMapFrame -> StackMapFrame 115
  • 116. Верификация байткода методом вывода типов Эти преобразователи дистрибутивны! 116
  • 117. Верификация байткода методом вывода типов Эти преобразователи дистрибутивны! Значит верификатор строит точное решение задачи верификации за конечное время без исполнения байткода! 117
  • 118. Верификация байткода методом вывода типов Эти преобразователи дистрибутивны! Значит верификатор строит точное решение задачи верификации за конечное время без исполнения байткода! Но за какое время? 118
  • 119. Оценка сложности алгоритма MFP Утверждение: Если обходить потоковый граф в глубину, то временная сложность алгоритма MFP (AMFP): T(AMFP) = O(BL*A*|V|), Где A – количество обратных дуг в потоковом графе A =O(|V|), на практике A ≤ 3
  • 120. Верификация байткода методом вывода типов Время работы верификатора зависит от: • Количества инструкций • Количества циклов • Количества локальных переменных • Максимальной глубины стека операндов • Высоты иерархии классов Дорого? 120
  • 121. Верификация байткода методом вывода типов Время работы верификатора зависит от: • Количества инструкций • Количества циклов • Количества локальных переменных • Максимальной глубины стека операндов • Высоты иерархии классов Дорого? 121
  • 123. Верификация байткода методом проверки типов Вопрос: Как ускорить верификатор? Идея: А что если мы знаем MFP решение верификатора методом вывода типов? Bingo! Тогда нам достаточно за один проход по байткоду проверить, что неподвижная точка (MFP) действительно неподвижная! (не меняется при применении преобразователей свойств инструкций) 123
  • 124. Верификация байткода методом проверки типов Вопрос: Как ускорить верификатор? Идея: А что если мы знаем MFP решение верификатора методом вывода типов? Bingo! Тогда нам достаточно за один проход по байткоду проверить, что неподвижная точка (MFP) действительно неподвижная! (не меняется при применении преобразователей свойств инструкций) 124
  • 125. Верификация байткода методом проверки типов Вопрос: Как ускорить верификатор? Идея: А что если мы знаем MFP решение верификатора методом вывода типов? Bingo! Тогда нам достаточно за один проход по байткоду проверить, что неподвижная точка (MFP) действительно неподвижная! (не меняется при применении преобразователей свойств инструкций) 125
  • 126. Верификация байткода методом проверки типов Split Verifier aka Type checking verifier: • У байткода версии Java 5 может быть атрибут StackMapTable (с Java 7 обязан быть) 126
  • 127. Верификация байткода методом проверки типов Split Verifier aka Type checking verifier: • У байткода версии Java 5 может быть атрибут StackMapTable (с Java 7 обязан быть) • StackMapTable – это список StackMapFrame 127
  • 128. Верификация байткода методом проверки типов Split Verifier aka Type checking verifier: • У байткода версии Java 5 может быть атрибут StackMapTable (с Java 7 обязан быть) • StackMapTable – это список StackMapFrame • StackMapFrame есть для каждой начальной инструкции линейных участков байткода, кроме первого 128
  • 129. Верификация байткода методом проверки типов Split aka Type checking verifier за один проход по байткоду: • вычисляет недостающие StackMapFrame: для каждой инструкции проверяет входящие типы, вычисляет исходящие (переносит ниже) • проверяет что StackMapFrame из StackMapTable атрибута не меняются при переносе StackMapFrame из инструкций выше (проверка неподвижности точки) 129
  • 130. Верификация байткода методом проверки типов Split aka Type checking verifier за один проход по байткоду: • вычисляет недостающие StackMapFrame: для каждой инструкции проверяет входящие типы, вычисляет исходящие (переносит ниже) • проверяет что StackMapFrame из StackMapTable атрибута не меняются при переносе StackMapFrame из инструкций выше (проверка неподвижности точки) 130
  • 132. Роль верификатора байткода в JVM Вопросы: 1. Может ли верификатор байткода замедлить исполнение ? 2. Может ли верификатор байткода замедлить старт? 3. Что было бы, если бы не было верификатора байткода? 4. А что будет, если его отключить? 132
  • 133. Роль верификатора байткода в JVM Вопрос: Может ли верификатор байткода замедлить исполнение? А исполнение чего? • Исполнение байткода метода • Исполнение горячего кода программы • Исполнение программы 133
  • 134. Роль верификатора байткода в JVM Вопрос: Может ли верификатор байткода замедлить исполнение? А исполнение чего? • Исполнение байткода метода • Исполнение горячего кода программы • Исполнение программы 134
  • 135. Роль верификатора байткода в JVM Вопрос: Может ли верификатор байткода замедлить исполнение? А исполнение чего? • Исполнение байткода метода • Исполнение горячего кода программы • Исполнение программы 135
  • 136. Роль верификатора байткода в JVM Вопрос: Может ли верификатор байткода замедлить исполнение байткода метода? Вспомним: Верификатор работает до исполнения! Ответ: Нет! 136
  • 137. Роль верификатора байткода в JVM Вопрос: Может ли верификатор байткода замедлить исполнение байткода метода? Вспомним: Верификатор работает до исполнения байткода! Ответ: Нет! 137
  • 138. Роль верификатора байткода в JVM Вопрос: Может ли верификатор байткода замедлить исполнение байткода метода? Вспомним: Верификатор работает до исполнения байткода! Ответ: Нет! 138
  • 139. Роль верификатора байткода в JVM Вопрос: Может ли верификатор байткода замедлить исполнение программы? 139
  • 140. Роль верификатора байткода в JVM Вопрос: Может ли верификатор байткода замедлить исполнение программы? Верификатор работает во время загрузки класса, загрузка классов работает во время исполнения программы 140
  • 141. Роль верификатора байткода в JVM Вопрос: Может ли верификатор байткода замедлить исполнение программы? Верификатор работает во время загрузки класса, загрузка классов работает во время исполнения программы Ответ: вообще говоря, да 141
  • 142. Роль верификатора байткода в JVM Вопрос: Может ли верификатор байткода замедлить исполнение горячего кода? 142
  • 143. Роль верификатора байткода в JVM Вопрос: Может ли верификатор байткода замедлить исполнение горячего кода? Во время исполнения горячего кода, все классы, с которым он работает, были загружены пока код был холодным. 143
  • 144. Роль верификатора байткода в JVM Вопрос: Может ли верификатор байткода замедлить исполнение горячего кода? Во время исполнения горячего кода, все классы, с которым он работает, были загружены пока код был холодным. Ответ: нет 144
  • 145. Роль верификатора байткода в JVM Вопрос: Может ли верификатор байткода замедлить старт программы? 145
  • 146. Верификатор и время старта 0 2 4 6 8 10 12 14 16 18 20 Eclipse 4.6 Cold Start Eclipse 4.6 Warm Start verify on verify:none 146 Время старта Eclipse 4.6 в секундах
  • 147. Верификатор и время старта 0 10 20 30 40 50 60 70 80 90 IntellIj IDEA 2016.3 Cold Start IntellIj IDEA 2016.3 Warm Start verify on verify:none 147 Время старта Intellij IDEA 2016.3 в секундах
  • 148. Роль верификатора байткода в JVM Вопрос: Может ли верификатор байткода замедлить старт программы? 148
  • 149. Роль верификатора байткода в JVM Вопрос: Может ли верификатор байткода замедлить старт программы? Ответ: незначительно 149
  • 150. Роль верификатора байткода в JVM Вопрос: Может ли верификатор байткода замедлить старт программы? Ответ: незначительно У JVM c AOT компилятором верификация на старте может не происходить 150
  • 151. Роль верификатора байткода в JVM Вопрос: Что было бы, если бы не было верификатора? 151
  • 152. Роль верификатора байткода в JVM Вопрос: Что было бы, если бы не было верификатора? Ответ: пришлось бы вставлять проверки во время исполнения: 152
  • 153. Роль верификатора байткода в JVM Вопрос: Что было бы, если бы не было верификатора? Ответ: пришлось бы вставлять проверки во время исполнения: • для инструкций работающих со стеком, проверять что стек не пуст и не переполнится 153
  • 154. Роль верификатора байткода в JVM Вопрос: Что было бы, если бы не было верификатора? Ответ: пришлось бы вставлять проверки во время исполнения: • для инструкций работающих со стеком, проверять что стек не пуст и не переполнится • для того, чтобы сложить два числа проверять, что на стеке лежат два числа 154
  • 155. Роль верификатора байткода в JVM Вопрос: Что было бы, если бы не было верификатора? Ответ: пришлось бы вставлять проверки во время исполнения: • для инструкций работающих со стеком, проверять что стек не пуст и не переполнится • для того, чтобы сложить два числа проверять, что на стеке лежат два числа Как бы быстро тогда работали Java программы? 155
  • 156. Роль верификатора байткода в JVM Факт: Интерпретатор не проверяет выходы за пределы стека операндов и типовую совместимость: если надо сложить два числа, он просто берет их со стека и складывает. 156
  • 157. Роль верификатора байткода в JVM Факт: Интерпретатор не проверяет выходы за пределы стека операндов и типовую совместимость: если надо сложить два числа, он просто берет их со стека и складывает. Факт: JIT компилятор при генерации машинного кода тоже не вставляет такие проверки в машинный код. 157
  • 158. Роль верификатора байткода в JVM Факт: Интерпретатор не проверяет выходы за пределы стека операндов и типовую совместимость: если надо сложить два числа, он просто берет их со стека и складывает. Факт: JIT компилятор при генерации машинного кода тоже не вставляет такие проверки в машинный код. Вывод: Наличие верификатора – первопричина почему JVM исполняет Java программы быстро! 158
  • 159. Роль верификатора байткода в JVM Вопрос: А что будет, если верификатор отключить? # A fatal error has been detected by the Java Runtime Environment: Exception in thread "main" java.lang.StackOverflowError at test.foo(test.j) at test.main(test.j:3) # # Internal Error (javaCalls.cpp:53), pid=8012, tid=16396 # guarantee(!thread->is_Compiler_thread()) failed: cannot make java calls from the compiler # 159
  • 160. Роль верификатора байткода в JVM Вопрос: А что будет, если верификатор отключить? # A fatal error has been detected by the Java Runtime Environment: Exception in thread "main" java.lang.StackOverflowError at test.foo(test.j) at test.main(test.j:3) # # Internal Error (javaCalls.cpp:53), pid=8012, tid=16396 # guarantee(!thread->is_Compiler_thread()) failed: cannot make java calls from the compiler # # If you would like to submit a bug report, please visit: # http://bugreport.java.com/bugreport/crash.jsp 160
  • 161. Роль верификатора байткода в JVM Вопрос: А что будет, если верификатор отключить? Ответ: Отключение верификатора может приводить к развалам JVM, что в свою очередь открывает потенциальные дыры в безопасности. 161
  • 162. Роль верификатора байткода в JVM Вопрос: А что будет, если верификатор отключить? Ответ: Отключение верификатора может приводить к развалам JVM, что в свою очередь открывает потенциальные дыры в безопасности. Вывод: Наличие верификатора делает исполнение байткода не только эффективным, но и безопасным! 162
  • 163. Верификатор и библиотеки генерации байткода
  • 164. Библиотеки генерации байткода • Низкоуровневые – ASM – BCEL • Высокоуровневые – Javassist – cglib – ByteBuddy 164
  • 165. ASM библиотека ASM библиотека • Позволяет полностью контролировать содержимое выходных классов, байткода 165
  • 166. ASM библиотека ASM библиотека • Позволяет полностью контролировать содержимое выходных классов, байткода • Как следствие низкоуровневая: вы работаете непосредственно с инструкциями байткода 166
  • 167. ASM библиотека ASM: пример кода MethodVisitor methodVisitor = … ; methodVisitor.visitVarInsn(Opcodes.ILOAD, 3); methodVisitor.visitIntInsn (Opcodes.BIPUSH, 5); methodVisitor.visitInsn (Opcodes.IADD); methodVisitor.visitVarInsn(Opcodes.ISTORE, 4); 167
  • 168. ASM библиотека • Нужно знать семантику байткодных инструкций • Легко породить неверифицируемый байткод • ASM умеет вычислять StackMapTable атрибут – с помощью того же потокового анализа • Можно задавать StackMapTable атрибут руками – для скорости; автоматическое вычисление замедляет ASM в 2 р. 168
  • 169. ASM библиотека • Нужно знать семантику байткодных инструкций • Легко породить неверифицируемый байткод • ASM умеет вычислять StackMapTable атрибут – с помощью того же потокового анализа • Можно задавать StackMapTable атрибут руками – для скорости; автоматическое вычисление замедляет ASM в 2 р. 169
  • 170. ASM библиотека • Нужно знать семантику байткодных инструкций • Легко породить неверифицируемый байткод • ASM умеет вычислять StackMapTable атрибут – с помощью того же потокового анализа • Можно задавать StackMapTable атрибут руками – для скорости; автоматическое вычисление замедляет ASM в 2 р. 170
  • 171. ASM библиотека • Нужно знать семантику байткодных инструкций • Легко породить неверифицируемый байткод • ASM умеет вычислять StackMapTable атрибут – с помощью того же потокового анализа • Можно задавать StackMapTable атрибут руками – для скорости; автоматическое вычисление замедляет ASM в 2 раза 171
  • 172. Библиотеки генерации байткода Проблема: некоторые (старые) библиотеки, манипулирующие байткодом, не умеют вычислять StackMapFramе 172
  • 173. Библиотеки генерации байткода Проблема: некоторые (старые) библиотеки, манипулирующие байткодом, не умеют вычислять StackMapFramе В результате вы можете получить ошибку: java.lang.VerifyError: Expecting a stackmap frame at branch 173
  • 174. Библиотеки генерации байткода Проблема: некоторые (старые) библиотеки, манипулирующие байткодом, не умеют вычислять StackMapFramе Можно отключить Typе Checking Verifier: -XX:-UseSplitVerifier 174
  • 175. Библиотеки генерации байткода Проблема: некоторые (старые) библиотеки, манипулирующие байткодом, не умеют вычислять StackMapFramе Можно отключить Typе Checking Verifier: -XX:-UseSplitVerifier Тогда будет работать Type Inference Verifier 175
  • 176. Библиотеки генерации байткода Проблема: некоторые (старые) библиотеки, манипулирующие байткодом, не умеют вычислять StackMapFramе Можно отключить Typе Checking Verifier: -XX:-UseSplitVerifier Тогда будет работать Type Inference Verifier – Развал JVM не случится 176
  • 177. Библиотеки генерации байткода Проблема: некоторые (старые) библиотеки, манипулирующие байткодом, не умеет вычислять StackMapFramе Можно отключить Typе Checking Verifier: -XX:-UseSplitVerifier Тогда будет работать Type Inference Verifier – Но старый верификатор не знает про invokedynamic – Случится VerifyError при использовании лямбд 177
  • 178. Библиотеки генерации байткода Проблема: некоторые (старые) библиотеки, манипулирующие байткодом, не умеет вычислять StackMapFramе Решение: не использовать старые библиотеки. Используя ASM, вычислять StackMapFramе самим или с помощью ASM. 178
  • 180. Заключение Верификатор Java байткода: • Незаслуженно обделенная вниманием часть JVM • Первопричина почему JVM исполняет программы быстро (практически на уровне низкоуровневых языков) • Гарантирует безопасность исполнения • Отключать верификатор не имеет никакого практического cмысла • Зная как работает верификатор, порождать байткод легко 180
  • 181. Заключение Верификатор Java байткода: • Незаслуженно обделенная вниманием часть JVM • Первопричина почему JVM исполняет программы быстро (практически на уровне низкоуровневых языков) • Гарантирует безопасность исполнения • Отключать верификатор не имеет никакого практического cмысла • Зная как работает верификатор, порождать байткод легко 181
  • 182. Заключение Верификатор Java байткода: • Незаслуженно обделенная вниманием часть JVM • Первопричина почему JVM исполняет программы быстро (практически на уровне низкоуровневых языков) • Гарантирует безопасность исполнения • Отключать верификатор не имеет никакого практического cмысла • Зная как работает верификатор, порождать байткод легко 182
  • 183. Заключение Верификатор Java байткода: • Незаслуженно обделенная вниманием часть JVM • Первопричина почему JVM исполняет программы быстро (практически на уровне низкоуровневых языков) • Гарантирует безопасность исполнения • Отключать верификатор не имеет никакого практического cмысла • Зная как работает верификатор, порождать байткод легко 183
  • 184. Заключение Верификатор Java байткода: • Незаслуженно обделенная вниманием часть JVM • Первопричина почему JVM исполняет программы быстро (практически на уровне низкоуровневых языков) • Гарантирует безопасность исполнения • Отключать верификатор не имеет никакого практического cмысла • Зная как работает верификатор, порождать байткод легко 184
  • 185. Заключение Верификатор Java байткода: • Незаслуженно обделенная вниманием часть JVM • Первопричина почему JVM исполняет программы быстро (практически на уровне низкоуровневых языков) • Гарантирует безопасность исполнения • Отключать верификатор не имеет никакого практического cмысла • Зная как работает верификатор, порождать байткод легко 185
  • 186. Вопросы и ответы Никита Липский, Excelsior nlipsky@excelsior-usa.com twitter: @pjBooms 186