Slide 1

Slide 1 text

Байткод для любознательных @antonarhipov Joker 2016, СПб

Slide 2

Slide 2 text

@antonarhipov Антон Архипов

Slide 3

Slide 3 text

Зачем? • Знай свою платформу! • Хотите написать свой компилятор? • Фреймворки (AOP, ORM) • Всевозможные инструменты (см. JRebel) • … ну или может просто скучно?

Slide 4

Slide 4 text

Основы Java-байткода Инструментарий ObjectWeb ASM

Slide 5

Slide 5 text

1 + 2

Slide 6

Slide 6 text

1 + 2 1 2 +

Slide 7

Slide 7 text

1 + 2 1 2 +

Slide 8

Slide 8 text

1 + 2 1 2 + PUSH 1 1

Slide 9

Slide 9 text

1 + 2 1 2 + PUSH 1 PUSH 2 2 1

Slide 10

Slide 10 text

1 + 2 1 2 + PUSH 1 PUSH 2 ADD 3

Slide 11

Slide 11 text

1 + 2 1 2 + ICONST_1 ICONST_2 IADD 3

Slide 12

Slide 12 text

? = 1 + 2

Slide 13

Slide 13 text

Таксономия

Slide 14

Slide 14 text

Работа со стеком Таксономия

Slide 15

Slide 15 text

Работа со стеком Инструкции управления Таксономия

Slide 16

Slide 16 text

Работа со стеком Инструкции управления Работа с объектами Таксономия

Slide 17

Slide 17 text

Работа со стеком Инструкции управления Арифметика Работа с объектами Таксономия

Slide 18

Slide 18 text

Работа со стеком Инструкции управления Арифметика Работа с объектами monitorenter monitorexit Таксономия

Slide 19

Slide 19 text

Байт-код • Одно-байтные инструкции • 256 возможных вариантов • Используется 200+ • Google: “Java bytecode instructions listings” • https://en.wikipedia.org/wiki/Java_bytecode_instruction_listings

Slide 20

Slide 20 text

• <тип> ::= b, s, c, i, l, f, d, a • Константы (ldc, iconst_1) • Локальные переменные и стек (load/store) • Операции с массивами (aaload, aastore) • Арифметика (add, sub, mul, div) • Булевые/битовые операции (iand, ixor) • Сравнения (cmpg, cmpl, ifne, ifeq) • Преобразования (l2d, i2l) ОПЕРАЦИЯ ТИП

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

JVM процесс

Slide 23

Slide 23 text

Thread 1 Thread 2 Thread 3 Thread 4

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

• JVM работает со стеком • У каждого потока есть стек • Стек сохраняет “фреймы” • Новый “фрейм” создаётся при вызове метода • “Фрейм” состоит из: – Стек операций – Массив локальных переменных Стековая машина

Slide 26

Slide 26 text

Стек операций Локальные переменные 2 0 1 N … Константы #1

Slide 27

Slide 27 text

Работа со стеком и локальными переменными

Slide 28

Slide 28 text

A B dup pop swap dup_x1 dup2_x1

Slide 29

Slide 29 text

A B dup pop swap dup_x1 dup2_x1 A

Slide 30

Slide 30 text

dup pop swap dup_x1 dup2_x1 A B

Slide 31

Slide 31 text

dup pop swap dup_x1 dup2_x1 A B

Slide 32

Slide 32 text

dup pop swap dup_x1 dup2_x1 A B B

Slide 33

Slide 33 text

dup pop swap dup_x1 dup2_x1 A B B B A

Slide 34

Slide 34 text

ldc "Hello" astore_0 iconst_1 astore_1 aload_0 глубина значение Стек переменная значение Локальные переменные 0 1 2 3 4 0 1 2 3 4

Slide 35

Slide 35 text

ldc "Hello" astore_0 iconst_1 astore_1 aload_0 "Hello" 0 1 2 3 4 0 1 2 3 4 глубина значение переменная значение Стек Локальные переменные

Slide 36

Slide 36 text

ldc "Hello" astore_0 iconst_1 astore_1 aload_0 "Hello" 0 1 2 3 4 0 1 2 3 4 глубина значение переменная значение Стек Локальные переменные

Slide 37

Slide 37 text

ldc "Hello" astore_0 iconst_1 astore_1 aload_0 "Hello" 0 1 2 3 4 0 1 2 3 4 1 глубина значение переменная значение Стек Локальные переменные

Slide 38

Slide 38 text

ldc "Hello" astore_0 iconst_1 astore_1 aload_0 "Hello" 0 1 2 3 4 0 1 2 3 4 1 глубина значение переменная значение Стек Локальные переменные

Slide 39

Slide 39 text

ldc "Hello" astore_0 iconst_1 astore_1 aload_0 "Hello" 0 1 2 3 4 0 1 2 3 4 1 "Hello" глубина значение переменная значение Стек Локальные переменные

Slide 40

Slide 40 text

Стек Таблица локальных переменных store load

Slide 41

Slide 41 text

Вызовы методов

Slide 42

Slide 42 text

invokeXXX • invokestatic • invokespecial • invokevirtual • invokeinterface • invokedynamic

Slide 43

Slide 43 text

invokestatic • invokestatic • invokespecial • invokevirtual • invokeinterface • invokedynamic Integer.valueOf(“42”)

Slide 44

Slide 44 text

invokespecial • invokestatic • invokespecial • invokevirtual • invokeinterface • invokedynamic private void foo(); super.method();

Slide 45

Slide 45 text

• invokestatic • invokespecial • invokevirtual • invokeinterface • invokedynamic invokevirtual class A class B A/method1 A/method2 A/method1 B/method2 B/method3

Slide 46

Slide 46 text

invokeinterface • invokestatic • invokespecial • invokevirtual • invokeinterface • invokedynamic Efficient Implementation of Java Interfaces: Invokeinterface Considered Harmless, Bowen Alpern, Anthony Cocchi, Stephen Fink, David Grove, and Derek Lieber, OOPSLA’01 class A class B impl X A/method1 A/method2 A/method1 B/method2 B/method3 X/methodX D impl X D/method1 X/methodX

Slide 47

Slide 47 text

Вызов метода

Slide 48

Slide 48 text

obj.method(param1, param2); Вызов метода

Slide 49

Slide 49 text

obj.method(param1, param2); Вызов метода

Slide 50

Slide 50 text

obj.method(param1, param2); push obj push param1 push param2 call method Вызов метода

Slide 51

Slide 51 text

obj.method(param1, param2); push obj push param1 push param2 call method obj Вызов метода

Slide 52

Slide 52 text

obj.method(param1, param2); push obj push param1 push param2 call method obj param1 Вызов метода

Slide 53

Slide 53 text

obj.method(param1, param2); push obj push param1 push param2 call method obj param1 param2 Вызов метода

Slide 54

Slide 54 text

obj.method(param1, param2); push obj push param1 push param2 call method obj? Вызов метода

Slide 55

Slide 55 text

this.add(1, 2); 0: aload_0 1: iconst_1 2: iconst_2 3: invokevirtual #2; //Method add:(II)I Вызов метода

Slide 56

Slide 56 text

Стек pop push

Slide 57

Slide 57 text

Стек Таблица локальных переменных store load pop push

Slide 58

Slide 58 text

Стек Таблица локальных переменных store load pop push

Slide 59

Slide 59 text

Стек Таблица локальных переменных store load pop push Стек Таблица локальных переменных store load pop push invoke

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 }

Slide 62

Slide 62 text

public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 } > javap -c Hello Дизассемблировать Hello

Slide 63

Slide 63 text

public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 } > javap -c Hello javap • Дизассемблер Java класс-файлов • По-умолчанию показывает только структуру класса – Методы, супер-класс, интерфейсы, итд • -c покажет байткод методов • -private покажет все приватные поля и методы • -s покажет сигнатуры • -l покажет номера строк и таблицу локальных переменных

Slide 64

Slide 64 text

public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 } > javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return

Slide 65

Slide 65 text

> javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return Конструктор по умолчанию public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 }

Slide 66

Slide 66 text

> javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return Выложить this на стек public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 }

Slide 67

Slide 67 text

> javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return Вызвать для Object public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 }

Slide 68

Slide 68 text

public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 } > javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return

Slide 69

Slide 69 text

public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 } > javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

Slide 70

Slide 70 text

> javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V Обратиться к статическому полю public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 }

Slide 71

Slide 71 text

> javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V Загрузить строковую константу в стек public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 }

Slide 72

Slide 72 text

> javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V Вызвать метод с параметром public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 }

Slide 73

Slide 73 text

public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 } > javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

Slide 74

Slide 74 text

> javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V Что такое #1,#2, итд ? public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 }

Slide 75

Slide 75 text

public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 } > javap -c -verbose Hello

Slide 76

Slide 76 text

public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 } > javap -c -verbose Hello Compiled from "Hello.java“ public class Hello extends java.lang.Object SourceFile: "Hello.java" minor version: 0 major version: 50 Constant pool: const #1 = Method #6.#20; // java/lang/Object."":()V const #2 = Field #21.#22; // java/lang/System.out:Ljava/io/PrintStream; const #3 = String #23; // Hello, World! const #4 = Method #24.#25; // java/io/PrintStream.println:(Ljava/lang/String;)V const #5 = class #26; // Hello const #6 = class #27; // java/lang/Object const #7 = Asciz ;

Slide 77

Slide 77 text

public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 } > javap -c -verbose Hello Compiled from "Hello.java“ public class Hello extends java.lang.Object SourceFile: "Hello.java" minor version: 0 major version: 50 Constant pool: const #1 = Method #6.#20; // java/lang/Object."":()V const #2 = Field #21.#22; // java/lang/System.out:Ljava/io/PrintStream; const #3 = String #23; // Hello, World! const #4 = Method #24.#25; // java/io/PrintStream.println:(Ljava/lang/String;)V const #5 = class #26; // Hello const #6 = class #27; // java/lang/Object const #7 = Asciz ;

Slide 78

Slide 78 text

public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 } > javap -c -verbose Hello public class Hello extends java.lang.Object … public Hello(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return LineNumberTable: line 1: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LHello;

Slide 79

Slide 79 text

public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 } > javap -c -verbose Hello public class Hello extends java.lang.Object … public Hello(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return LineNumberTable: line 1: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LHello;

Slide 80

Slide 80 text

public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 } > javap -c -verbose Hello public class Hello extends java.lang.Object … public Hello(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return LineNumberTable: line 1: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LHello;

Slide 81

Slide 81 text

public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 } > javap -c -verbose Hello public class Hello extends java.lang.Object … public Hello(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return LineNumberTable: line 1: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LHello;

Slide 82

Slide 82 text

No content

Slide 83

Slide 83 text

Java Bytecode Editor — http://set.ee/jbe/

Slide 84

Slide 84 text

IntelliJ IDEA: ASM Bytecode Outline plugin

Slide 85

Slide 85 text

public java.lang.String getName(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: getfield #2; //Field name:Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LGet; public class Get {
 String name; 
 public String getName() {
 return name;
 }
 }

Slide 86

Slide 86 text

aload_0 getfield 00 02 areturn 0 1 2 3 4 public java.lang.String getName(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: getfield #2; //Field name:Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LGet;

Slide 87

Slide 87 text

2A B4 public java.lang.String getName(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: getfield #2; //Field name:Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LGet; 00 02 0 1 2 3 4 B0

Slide 88

Slide 88 text

public java.lang.String getName(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: getfield #2; //Field name:Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LGet;

Slide 89

Slide 89 text

No content

Slide 90

Slide 90 text

ObjectWeb ASM • Низкоуровневый фреймворк для манипуляций и анализа Java-байткода • Стандарт de facto • http://asm.ow2.org

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

Зачем манипулировать байткодом (ещё раз) • Профилировщики • Агенты для мониторинга • Дебаггеры • Фреймворки • JRebel Требуется внедрение функциональности в работающий код

Slide 93

Slide 93 text

ASM: общий сценарий Создать ClassWriter Скомпоновать visitor-ы: аннотации, поля, методы, итд Генерировать новый байткод 1 2 3

Slide 94

Slide 94 text

Class Reader Class Visitor

Slide 95

Slide 95 text

Class Writer Class Visitor Class Visitor Class Reader

Slide 96

Slide 96 text

Class Writer Class Visitor Class Visitor Class Reader Class Visitor Class Visitor

Slide 97

Slide 97 text

Class Writer Class Visitor Class Visitor Class Reader Class Visitor Class Visitor Class Visitor Class Visitor Class Visitor Class Visitor Class Visitor Class Reader Class Writer

Slide 98

Slide 98 text

ClassVisitor visit visitSource visitOuterClass visitAnnotation visitAttribute visitInnerClass visitField visitMethod visitEnd ClassReader

Slide 99

Slide 99 text

ClassVisitor visit visitSource visitOuterClass visitAnnotation visitAttribute visitInnerClass visitField visitMethod visitEnd AnnotationVisitor FieldVisitor MethodVisitor ClassReader

Slide 100

Slide 100 text

No content

Slide 101

Slide 101 text

https://github.com/antonarhipov/asmdemo

Slide 102

Slide 102 text

No content