the bytecode
gobbledygook
#perfmatters
@rrafols
Disclaimer:
This presentation contains
bytecode
Content is my own experimentation and
might differ on other environments
Competitions
Work
2015 Local winner
2016+ Ambassador
2016 Runner up
2018 Honorable mention
Demoscene
Speaker
Author Entrepreneurship
@rrafols
Everything starts with our
friend the java compiler.
*.java → [javac] → *.class
Or on Android
*.java → [javac] → *.class
*.class → [dx] → dex file
*.java → [javac] → *.class
*.class → [dx] → dex
dex → [dexopt] → opt. dex
dex → [dex2oat] → native
but change is coming!
Jack & Jill
but change is coming!
Jack & Jill
*.java → [jack] → dex file
but change is still coming!
D8 & R8
*.java → [javac] → *.class
*.class → [d8/r8] → dex file
Let’s focus first on javac
Javac vs other compilers
Compilers
Produces optimized code
for the target platform
javac
Does not produce
optimized code*
javac
Does not know on which
architecture the code will
be executed
Source: Oracle
For this reason
Java bytecode &
operations are stack
based
Easy to interpret
But not the most
performant solution
Quick example
Stack based integer
addition
j = j + i
Java bytecode
iload_3
iload_2
iadd
istore_2
Register based approach
add r01, r02, r01
or
add eax, ebx
Let’s make things
interesting…
j = j + i + k + w + h * 2 + p * p;
Java bytecode
0: iload_2
1: iload_1
2: iadd
3: iload_3
4: iadd
5: iload 4
7: iadd
8: iload 5
10: iconst_2
11: imul
12: iadd
13: iload 6
15: iload 6
17: imul
18: iadd
19: istore_2
j = j + i + k + w + h * 2 + p * p;
Local vars
1: i
2: j
3: k
4: w
5: h
6: p
0: iload_2
1: iload_1
2: iadd
3: iload_3
4: iadd
5: iload 4
7: iadd
8: iload 5
10: iconst_2
11: imul
12: iadd
13: iload 6
15: iload 6
17: imul
18: iadd
19: istore_2
j = j + i + k + w + h * 2 + p * p;
Local vars
1: i
2: j
3: k
4: w
5: h
6: p
0: iload_2
1: iload_1
2: iadd
3: iload_3
4: iadd
5: iload 4
7: iadd
8: iload 5
10: iconst_2
11: imul
12: iadd
13: iload 6
15: iload 6
17: imul
18: iadd
19: istore_2
j = j + i + k + w + h * 2 + p * p;
Local vars
1: i
2: j
3: k
4: w
5: h
6: p
0: iload_2
1: iload_1
2: iadd
3: iload_3
4: iadd
5: iload 4
7: iadd
8: iload 5
10: iconst_2
11: imul
12: iadd
13: iload 6
15: iload 6
17: imul
18: iadd
19: istore_2
j = j + i + k + w + h * 2 + p * p;
Local vars
1: i
2: j
3: k
4: w
5: h
6: p
0: iload_2
1: iload_1
2: iadd
3: iload_3
4: iadd
5: iload 4
7: iadd
8: iload 5
10: iconst_2
11: imul
12: iadd
13: iload 6
15: iload 6
17: imul
18: iadd
19: istore_2
j = j + i + k + w + h * 2 + p * p;
Local vars
1: i
2: j
3: k
4: w
5: h
6: p
0: iload_2
1: iload_1
2: iadd
3: iload_3
4: iadd
5: iload 4
7: iadd
8: iload 5
10: iconst_2
11: imul
12: iadd
13: iload 6
15: iload 6
17: imul
18: iadd
19: istore_2
j = j + i + k + w + h * 2 + p * p;
Local vars
1: i
2: j
3: k
4: w
5: h
6: p
0: iload_2
1: iload_1
2: iadd
3: iload_3
4: iadd
5: iload 4
7: iadd
8: iload 5
10: iconst_2
11: imul
12: iadd
13: iload 6
15: iload 6
17: imul
18: iadd
19: istore_2
j = j + i + k + w + h * 2 + p * p;
Local vars
1: i
2: j
3: k
4: w
5: h
6: p
Register based approach
add r01, r02, r01
add r01, r03, r01
add r01, r04, r01
mul r07, r05, #2
add r01, r07, r01
mul r08, r06, r06
add r02, r08, r01
j = j + i + k + w + h * 2 + p * p;
r01: i
r02: j
r03: k
r04: w
r05: h
r06: p
Java VM (JVM)
Only the JVM knows the
architecture where is running.
In our previous example, we used up to
8 registers, but some CPUs might have
less than 8 registers…
Java VM (JVM)
All optimizations are left to
be done by the JVM
Maybe takes this concept
a bit too far...
Imagine this simple C code
#include <stdio.h>
int main() {
int a = 10;
int b = 1 + 2 + 3 + 4 + 5 + 6 + a;
printf("%dn", b);
}
GCC compiler
#include <stdio.h>
int main() {
int a = 10;
int b = 1 + 2 + 3 + 4 + 5 + 6 + a;
printf("%dn", b);
}
…
movl $31, %esi
call _printf
…
* Using gcc & -O2 compiler option
javac
public static void main(String
args[]) {
int a = 10;
int b = 1 + 2 + 3 + 4 + 5 + 6 + a;
System.out.println(b);
}
0: bipush 10
2: istore_1
3: bipush 21
5: iload_1
6: iadd
7: istore_2
...
Let's do a small change
#include <stdio.h>
int main() {
int a = 10;
int b = 1 + 2 + 3 + 4 + 5 + a + 6;
printf("%dn", b);
}
GCC compiler
#include <stdio.h>
int main() {
int a = 10;
int b = 1 + 2 + 3 + 4 + 5 + a + 6;
printf("%dn", b);
}
…
movl $31, %esi
call _printf
…
* Using gcc & -O2 compiler option
javac
public static void main(String
args[]) {
int a = 10;
int b = 1 + 2 + 3 + 4 + 5 + a + 6;
System.out.println(b);
}
0: bipush 10
2: istore_1
3: bipush 15
5: iload_1
6: iadd
7: bipush 6
9: iadd
10: istore_2
Let's do another quick
change..
public static void main(String args[]) {
int a = 10;
int b = a + 1 + 2 + 3 + 4 + 5 + 6;
System.out.println(b);
}
javac
00: bipush 10
02: istore_1
03: iload_1
04: iconst_1
05: iadd
06: iconst_2
07: iadd
08: iconst_3
09: iadd
10: iconst_4
11: iadd
12: iconst_5
13: iadd
14: bipush 6
16: iadd
17: istore_2
public static void main(String args[]) {
int a = 10;
int b = a + 1 + 2 + 3 + 4 + 5 + 6;
System.out.println(b);
}
On Android there was
jack to the rescue...
jack
public static void main(String args[]) {
int a = 10;
int b = a + 1 + 2 + 3 + 4 + 5 + 6;
System.out.println(b);
}
...
0: const/16 v0, #int 31
2: sget-object v1,
Ljava/lang/System;
4: invoke-virtual {v1, v0}
7: return-void
...
but d8 does the
job as well...
d8
public static void main(String args[]) {
int a = 10;
int b = a + 1 + 2 + 3 + 4 + 5 + 6;
System.out.println(b);
}
...
0: sget-object v1,
Ljava/lang/System;…
2: const/16 v0, #int 31
4: invoke-virtual {v1, v0}
7: return-void
...
And on Java there is the
JIT compiler to the rescue
JIT assembly output
public static void main(String args[]) {
int a = 10;
int b = a + 1 + 2 + 3 + 4 + 5 + 6;
System.out.println(b);
}
...
0x00000001104b2bff: mov eax, 0x0001f
...
0: bipush 10
2: istore_1
3: iload_1
4: iconst_1
5: iadd
6: iconst_2
7: iadd
8: iconst_3
9: iadd
10: iconst_4
11: iadd
12: iconst_5
13: iadd
14: bipush 6
16: iadd
17: istore_2
Language additions
Thinks to consider
Autoboxing
Transparent to the developer
but compiler adds some
'extra' code
Autoboxing
long total = 0;
for(int i = 0; i < N; i++) {
total += i;
}
0: lconst_0
1: lstore_1
2: iconst_0
3: istore_3
4: iload_3
5: ldc #8 // N
7: if_icmpge 21
10: lload_1
11: iload_3
12: i2l
13: ladd
14: lstore_1
15: iinc 3, 1
18: goto 4
Autoboxing
long total = 0;
for(int i = 0; i < N; i++) {
total += i;
}
0: lconst_0
1: lstore_1
2: iconst_0
3: istore_3
4: iload_3
5: ldc #8 // N
7: if_icmpge 21
10: lload_1
11: iload_3
12: i2l
13: ladd
14: lstore_1
15: iinc 3, 1
18: goto 4
Autoboxing
long total = 0;
for(int i = 0; i < N; i++) {
total += i;
}
0: lconst_0
1: lstore_1
2: iconst_0
3: istore_3
4: iload_3
5: ldc #8 // N
7: if_icmpge 21
10: lload_1
11: iload_3
12: i2l
13: ladd
14: lstore_1
15: iinc 3, 1
18: goto 4
Autoboxing
long total = 0;
for(int i = 0; i < N; i++) {
total += i;
}
0: lconst_0
1: lstore_1
2: iconst_0
3: istore_3
4: iload_3
5: ldc #8 // N
7: if_icmpge 21
10: lload_1
11: iload_3
12: i2l
13: ladd
14: lstore_1
15: iinc 3, 1
18: goto 4
21:
Autoboxing
long total = 0;
for(int i = 0; i < N; i++) {
total += i;
}
0: lconst_0
1: lstore_1
2: iconst_0
3: istore_3
4: iload_3
5: ldc #8 // N
7: if_icmpge 21
10: lload_1
11: iload_3
12: i2l
13: ladd
14: lstore_1
15: iinc 3, 1
18: goto 4
Autoboxing
long total = 0;
for(int i = 0; i < N; i++) {
total += i;
}
0: lconst_0
1: lstore_1
2: iconst_0
3: istore_3
4: iload_3
5: ldc #8 // N
7: if_icmpge 21
10: lload_1
11: iload_3
12: i2l
13: ladd
14: lstore_1
15: iinc 3, 1
18: goto 4
Autoboxing
long total = 0;
for(int i = 0; i < N; i++) {
total += i;
}
0: lconst_0
1: lstore_1
2: iconst_0
3: istore_3
4: iload_3
5: ldc #8 // N
7: if_icmpge 21
10: lload_1
11: iload_3
12: i2l
13: ladd
14: lstore_1
15: iinc 3, 1
18: goto 4
Autoboxing
Long total = 0;
for(Integer i = 0; i < N; i++) {
total += i;
}
Autoboxing
Long total = 0;
for(Integer i = 0; i < N; i++) {
total += i;
}
00: lconst_0
01: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la
04: astore_1
05: iconst_0
06: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/
09: astore_2
10: aload_2
11: invokevirtual #9 // java/lang/Integer.intValue:()I
14: sipush N
17: if_icmpge 54
20: aload_1
21: invokevirtual #10 // java/lang/Long.longValue:()J
24: aload_2
25: invokevirtual #9 // java/lang/Integer.intValue:()I
28: i2l
29: ladd
30: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la
33: astore_1
34: aload_2
35: astore_3
36: aload_2
37: invokevirtual #9 // java/lang/Integer.intValue:()I
40: iconst_1
41: iadd
42: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/
45: dup
46: astore_2
47: astore 4
49: aload_3
50: pop
51: goto 10
Autoboxing
Long total = 0;
for(Integer i = 0; i < N; i++) {
total += i;
}
00: lconst_0
01: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la
04: astore_1
05: iconst_0
06: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/
09: astore_2
10: aload_2
11: invokevirtual #9 // java/lang/Integer.intValue:()I
14: sipush N
17: if_icmpge 54
20: aload_1
21: invokevirtual #10 // java/lang/Long.longValue:()J
24: aload_2
25: invokevirtual #9 // java/lang/Integer.intValue:()I
28: i2l
29: ladd
30: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la
33: astore_1
34: aload_2
35: astore_3
36: aload_2
37: invokevirtual #9 // java/lang/Integer.intValue:()I
40: iconst_1
41: iadd
42: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/
45: dup
46: astore_2
47: astore 4
49: aload_3
50: pop
51: goto 10
Autoboxing
Long total = 0;
for(Integer i = 0; i < N; i++) {
total += i;
}
00: lconst_0
01: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la
04: astore_1
05: iconst_0
06: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/
09: astore_2
10: aload_2
11: invokevirtual #9 // java/lang/Integer.intValue:()I
14: sipush N
17: if_icmpge 54
20: aload_1
21: invokevirtual #10 // java/lang/Long.longValue:()J
24: aload_2
25: invokevirtual #9 // java/lang/Integer.intValue:()I
28: i2l
29: ladd
30: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la
33: astore_1
34: aload_2
35: astore_3
36: aload_2
37: invokevirtual #9 // java/lang/Integer.intValue:()I
40: iconst_1
41: iadd
42: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/
45: dup
46: astore_2
47: astore 4
49: aload_3
50: pop
51: goto 10
Autoboxing
Long total = 0;
for(Integer i = 0; i < N; i++) {
total += i;
}
00: lconst_0
01: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la
04: astore_1
05: iconst_0
06: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/
09: astore_2
10: aload_2
11: invokevirtual #9 // java/lang/Integer.intValue:()I
14: sipush N
17: if_icmpge 54
20: aload_1
21: invokevirtual #10 // java/lang/Long.longValue:()J
24: aload_2
25: invokevirtual #9 // java/lang/Integer.intValue:()I
28: i2l
29: ladd
30: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la
33: astore_1
34: aload_2
35: astore_3
36: aload_2
37: invokevirtual #9 // java/lang/Integer.intValue:()I
40: iconst_1
41: iadd
42: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/
45: dup
46: astore_2
47: astore 4
49: aload_3
50: pop
51: goto 10
Autoboxing
Long total = 0;
for(Integer i = 0; i < N; i++) {
total += i;
}
00: lconst_0
01: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la
04: astore_1
05: iconst_0
06: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/
09: astore_2
10: aload_2
11: invokevirtual #9 // java/lang/Integer.intValue:()I
14: sipush N
17: if_icmpge 54
20: aload_1
21: invokevirtual #10 // java/lang/Long.longValue:()J
24: aload_2
25: invokevirtual #9 // java/lang/Integer.intValue:()I
28: i2l
29: ladd
30: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la
33: astore_1
34: aload_2
35: astore_3
36: aload_2
37: invokevirtual #9 // java/lang/Integer.intValue:()I
40: iconst_1
41: iadd
42: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/
45: dup
46: astore_2
47: astore 4
49: aload_3
50: pop
51: goto 10
Autoboxing
Long total = 0;
for(Integer i = 0; i < N; i++) {
total += i;
}
00: lconst_0
01: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la
04: astore_1
05: iconst_0
06: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/
09: astore_2
10: aload_2
11: invokevirtual #9 // java/lang/Integer.intValue:()I
14: sipush N
17: if_icmpge 54
20: aload_1
21: invokevirtual #10 // java/lang/Long.longValue:()J
24: aload_2
25: invokevirtual #9 // java/lang/Integer.intValue:()I
28: i2l
29: ladd
30: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la
33: astore_1
34: aload_2
35: astore_3
36: aload_2
37: invokevirtual #9 // java/lang/Integer.intValue:()I
40: iconst_1
41: iadd
42: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/
45: dup
46: astore_2
47: astore 4
49: aload_3
50: pop
51: goto 10
Autoboxing
Long total = 0;
for(Integer i = 0; i < N; i++) {
total += i;
}
00: lconst_0
01: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la
04: astore_1
05: iconst_0
06: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/
09: astore_2
10: aload_2
11: invokevirtual #9 // java/lang/Integer.intValue:()I
14: sipush N
17: if_icmpge 54
20: aload_1
21: invokevirtual #10 // java/lang/Long.longValue:()J
24: aload_2
25: invokevirtual #9 // java/lang/Integer.intValue:()I
28: i2l
29: ladd
30: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la
33: astore_1
34: aload_2
35: astore_3
36: aload_2
37: invokevirtual #9 // java/lang/Integer.intValue:()I
40: iconst_1
41: iadd
42: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/
45: dup
46: astore_2
47: astore 4
49: aload_3
50: pop
51: goto 10
Autoboxing
Long total = 0;
for(Integer i = 0; i < N; i++) {
total += i;
}
// ?
00: lconst_0
01: invokestatic #7 // Method java/lang/Long.valueOf:(J)L
04: astore_1
05: iconst_0
06: invokestatic #8 // Method java/lang/Integer.valueOf:(I
09: astore_2
10: aload_2
11: invokevirtual #9 // Method java/lang/Integer.intValue:
14: sipush N
17: if_icmpge 54
20: aload_1
21: invokevirtual #10 // Method java/lang/Long.longValue:(
24: aload_2
25: invokevirtual #9 // Method java/lang/Integer.intValue:
28: i2l
29: ladd
30: invokestatic #7 // Method java/lang/Long.valueOf:(J)L
33: astore_1
34: aload_2
35: astore_3
36: aload_2
37: invokevirtual #9 // Method java/lang/Integer.intValue:
40: iconst_1
41: iadd
42: invokestatic #8 // Method java/lang/Integer.valueOf:(I
45: dup
46: astore_2
47: astore 4
49: aload_3
50: pop
51: goto 10
Autoboxing
This is what that code is actually doing:
Long total = Long.valueOf(0);
for(Integer i = Integer.valueOf(0);
i.intValue() < N;
i = Integer.valueOf(i.intValue() + 1)) {
total = Long.valueOf(total.longValue() + (long)i.intValue())
}
Autoboxing
Object creation
Long total = Long.valueOf(0);
for(Integer i = Integer.valueOf(0);
i.intValue() < N;
i = Integer.valueOf(i.intValue() + 1)) {
total = Long.valueOf(total.longValue() + (long)i.intValue())
}
Autoboxing
What about dex bytecode?
Autoboxing
D8 does not help in this situation
(neither Jack)
Autoboxing
What about the JIT compiler on
plain java?
Autoboxing
Let's run that loop
N times
(on my desktop computer)
N = 10.000.000.000
Autoboxing
Autoboxing
Let’s try it on Android
Dalvik VM & ART
Autoboxing
Language Additions
Use them wisely!
Sorting
No bytecode mumbo-jumbo
here
Let's sort some numbers…
Arrays.sort(...)
Difference between sorting
primitive types (int) &
objects (Integer)
Using int & Integer
When sorting objects java
uses a stable sort
Default java algorithm:
TimSort adaptation
Sorting primitives does not
require to be stable sort
Default java algorithm:
Dual-Pivot quicksort
Sorting
Use primitive types as much
as possible
Loops
What is going on behind the
scenes
Loops - List
ArrayList<Integer> list = new …
static long loopStandardList() {
long result = 0;
for(int i = 0; i < list.size(); i++) {
result += list.get(i);
}
return result;
}
ArrayList<Integer> list = new …
static long loopStandardList() {
long result = 0;
for(int i = 0; i < list.size(); i++) {
result += list.get(i);
}
return result;
}
07: lload_0
08: getstatic list
11: iload_2
12: invokevirtual java/util/ArrayList.get
15: checkcast java/lang/Integer
18: invokevirtual java/lang/Integer.intValue
21: i2l
22: ladd
23: lstore_0
24: iinc 2, 1
27: iload_2
28: getstatic list
31: invokevirtual java/util/ArrayList.size
34: if_icmplt 7
Loops - List
ArrayList<Integer> list = new …
static long loopStandardList() {
long result = 0;
for(int i = 0; i < list.size(); i++) {
result += list.get(i);
}
return result;
}
Loops - List 07: lload_0
08: getstatic list
11: iload_2
12: invokevirtual java/util/ArrayList.get
15: checkcast java/lang/Integer
18: invokevirtual java/lang/Integer.intValue
21: i2l
22: ladd
23: lstore_0
24: iinc 2, 1
27: iload_2
28: getstatic list
31: invokevirtual java/util/ArrayList.size
34: if_icmplt 7
ArrayList<Integer> list = new …
static long loopStandardList() {
long result = 0;
for(int i = 0; i < list.size(); i++) {
result += list.get(i);
}
return result;
}
Loops - List 07: lload_0
08: getstatic list
11: iload_2
12: invokevirtual java/util/ArrayList.get
15: checkcast java/lang/Integer
18: invokevirtual java/lang/Integer.intValue
21: i2l
22: ladd
23: lstore_0
24: iinc 2, 1
27: iload_2
28: getstatic list
31: invokevirtual java/util/ArrayList.size
34: if_icmplt 7
ArrayList<Integer> list = new …
static long loopStandardList() {
long result = 0;
for(int i = 0; i < list.size(); i++) {
result += list.get(i);
}
return result;
}
Loops - List 07: lload_0
08: getstatic list
11: iload_2
12: invokevirtual java/util/ArrayList.get
15: checkcast java/lang/Integer
18: invokevirtual java/lang/Integer.intValue
21: i2l
22: ladd
23: lstore_0
24: iinc 2, 1
27: iload_2
28: getstatic list
31: invokevirtual java/util/ArrayList.size
34: if_icmplt 7
Loops - foreach
ArrayList<Integer> list = new …
static long loopForeachList() {
long result = 0;
for(int v : list) {
result += v;
}
return result;
}
ArrayList<Integer> list = new …
static long loopForeachList() {
long result = 0;
for(int v : list) {
result += v;
}
return result;
}
12: aload_3
13: invokeinterface java/util/Iterator.next
18: checkcast java/lang/Integer
21: invokevirtual java/lang/Integer.intValue
24: istore_2
25: lload_0
26: iload_2
27: i2l
28: ladd
29: lstore_0
30: aload_3
31: invokeinterface java/util/Iterator.hasNext
36: ifne 12
Loops - foreach
ArrayList<Integer> list = new …
static long loopForeachList() {
long result = 0;
for(int v : list) {
result += v;
}
return result;
}
Loops - foreach
12: aload_3
13: invokeinterface java/util/Iterator.next
18: checkcast java/lang/Integer
21: invokevirtual java/lang/Integer.intValue
24: istore_2
25: lload_0
26: iload_2
27: i2l
28: ladd
29: lstore_0
30: aload_3
31: invokeinterface java/util/Iterator.hasNext
36: ifne 12
ArrayList<Integer> list = new …
static long loopForeachList() {
long result = 0;
for(int v : list) {
result += v;
}
return result;
}
Loops - foreach
12: aload_3
13: invokeinterface java/util/Iterator.next
18: checkcast java/lang/Integer
21: invokevirtual java/lang/Integer.intValue
24: istore_2
25: lload_0
26: iload_2
27: i2l
28: ladd
29: lstore_0
30: aload_3
31: invokeinterface java/util/Iterator.hasNext
36: ifne 12
Loops - Array
static int[] array = new ...
static long loopStandardArray() {
long result = 0;
for(int i = 0; i < array.length; i++) {
result += array[i];
}
return result;
}
static int[] array = new ...
static long loopStandardArray() {
long result = 0;
for(int i = 0; i < array.length; i++) {
result += array[i];
}
return result;
}
07: lload_0
08: getstatic array
11: iload_2
12: iaload
13: i2l
14: ladd
15: lstore_0
16: iinc 2, 1
19: iload_2
20: getstatic array
23: arraylength
24: if_icmplt 7
Loops - Array
static int[] array = new ...
static long loopStandardArray() {
long result = 0;
for(int i = 0; i < array.length; i++) {
result += array[i];
}
return result;
}
Loops - Array
07: lload_0
08: getstatic array
11: iload_2
12: iaload
13: i2l
14: ladd
15: lstore_0
16: iinc 2, 1
19: iload_2
20: getstatic array
23: arraylength
24: if_icmplt 7
static int[] array = new ...
static long loopStandardArray() {
long result = 0;
for(int i = 0; i < array.length; i++) {
result += array[i];
}
return result;
}
Loops - Array
07: lload_0
08: getstatic array
11: iload_2
12: iaload
13: i2l
14: ladd
15: lstore_0
16: iinc 2, 1
19: iload_2
20: getstatic array
23: arraylength
24: if_icmplt 7
Loops - size cached
static int[] array = new ...
static long loopStandardArray () {
long result = 0;
int length = array.length;
for(int i = 0; i < length; i++) {
result += array[i];
}
return result;
}
static int[] array = new ...
static long loopStandardArray () {
long result = 0;
int length = array.length;
for(int i = 0; i < length; i++) {
result += array[i];
}
return result;
}
12: lload_0
13: getstatic array
16: iload_3
17: iaload
18: i2l
19: ladd
20: lstore_0
21: iinc 3, 1
24: iload_3
25: iload_2
26: if_icmplt 12
Loops - size cached
static int[] array = new ...
static long loopStandardArray () {
long result = 0;
int length = array.length;
for(int i = 0; i < length; i++) {
result += array[i];
}
return result;
}
Loops - size cached
12: lload_0
13: getstatic array
16: iload_3
17: iaload
18: i2l
19: ladd
20: lstore_0
21: iinc 3, 1
24: iload_3
25: iload_2
26: if_icmplt 12
Loops - backwards
static int[] array = new ...
static long loopStandardArray () {
long result = 0;
for(int i = array.length - 1; i >= 0; i--) {
result += array[i];
}
return result;
}
static int[] array = new ...
static long loopStandardArray () {
long result = 0;
for(int i = array.length - 1; i >= 0; i--) {
result += array[i];
}
return result;
}
12: lload_0
13: getstatic array
16: iload_2
17: iaload
18: i2l
19: ladd
20: lstore_0
21: iinc 2, -1
24: iload_2
25: ifge 12
Loops - backwards
static int[] array = new ...
static long loopStandardArray () {
long result = 0;
for(int i = array.length - 1; i >= 0; i--) {
result += array[i];
}
return result;
}
Loops - backwards
12: lload_0
13: getstatic array
16: iload_2
17: iaload
18: i2l
19: ladd
20: lstore_0
21: iinc 2, -1
24: iload_2
25: ifge 12
Let’s check step by step…
Loops – foreach II
static long loopForeachArray(int[] array) {
long result = 0;
for(int v : array) {
result += v;
}
return result;
}
Loops – foreach II
static long loopForeachArray(int[] array) {
long result = 0;
for(int v : array) {
result += v;
}
return result;
}
00: lconst_0
01: lstore_1
02: aload_0
03: dup
04: astore 6
06: arraylength
07: istore 5
09: iconst_0
10: istore 4
12: goto 29
15: aload 6
17: iload 4
19: iaload
20: istore_3
21: lload_1
22: iload_3
23: i2l
24: ladd
25: lstore_1
26: iinc 4, 1
29: iload 4
31: iload 5
33: if_icmplt 15
0 array 4 -
1 - 5 -
2 - 6 -
3 - 7 -
Loops – foreach II
static long loopForeachArray(int[] array) {
long result = 0;
for(int v : array) {
result += v;
}
return result;
}
00: lconst_0
01: lstore_1
02: aload_0
03: dup
04: astore 6
06: arraylength
07: istore 5
09: iconst_0
10: istore 4
12: goto 29
15: aload 6
17: iload 4
19: iaload
20: istore_3
21: lload_1
22: iload_3
23: i2l
24: ladd
25: lstore_1
26: iinc 4, 1
29: iload 4
31: iload 5
33: if_icmplt 15
0 array 4 -
1 0 (result) 5 -
2 - 6 -
3 - 7 -
Loops – foreach II
static long loopForeachArray(int[] array) {
long result = 0;
for(int v : array) {
result += v;
}
return result;
}
00: lconst_0
01: lstore_1
02: aload_0
03: dup
04: astore 6
06: arraylength
07: istore 5
09: iconst_0
10: istore 4
12: goto 29
15: aload 6
17: iload 4
19: iaload
20: istore_3
21: lload_1
22: iload_3
23: i2l
24: ladd
25: lstore_1
26: iinc 4, 1
29: iload 4
31: iload 5
33: if_icmplt 15
0 array 4 -
1 0 (result) 5 -
2 - 6 array
3 - 7 -
Loops – foreach II
static long loopForeachArray(int[] array) {
long result = 0;
for(int v : array) {
result += v;
}
return result;
}
00: lconst_0
01: lstore_1
02: aload_0
03: dup
04: astore 6
06: arraylength
07: istore 5
09: iconst_0
10: istore 4
12: goto 29
15: aload 6
17: iload 4
19: iaload
20: istore_3
21: lload_1
22: iload_3
23: i2l
24: ladd
25: lstore_1
26: iinc 4, 1
29: iload 4
31: iload 5
33: if_icmplt 15
0 array 4 -
1 0 (result) 5 array.length
2 - 6 array
3 - 7 -
Loops – foreach II
static long loopForeachArray(int[] array) {
long result = 0;
for(int v : array) {
result += v;
}
return result;
}
00: lconst_0
01: lstore_1
02: aload_0
03: dup
04: astore 6
06: arraylength
07: istore 5
09: iconst_0
10: istore 4
12: goto 29
15: aload 6
17: iload 4
19: iaload
20: istore_3
21: lload_1
22: iload_3
23: i2l
24: ladd
25: lstore_1
26: iinc 4, 1
29: iload 4
31: iload 5
33: if_icmplt 15
0 array 4 0 (loop index)
1 0 (result) 5 array.length
2 - 6 array
3 - 7 -
Loops – foreach II
static long loopForeachArray(int[] array) {
long result = 0;
for(int v : array) {
result += v;
}
return result;
}
00: lconst_0
01: lstore_1
02: aload_0
03: dup
04: astore 6
06: arraylength
07: istore 5
09: iconst_0
10: istore 4
12: goto 29
15: aload 6
17: iload 4
19: iaload
20: istore_3
21: lload_1
22: iload_3
23: i2l
24: ladd
25: lstore_1
26: iinc 4, 1
29: iload 4
31: iload 5
33: if_icmplt 15
0 array 4 0 (loop index)
1 0 (result) 5 array.length
2 - 6 array
3 - 7 -
Loops – foreach II
static long loopForeachArray(int[] array) {
long result = 0;
for(int v : array) {
result += v;
}
return result;
}
00: lconst_0
01: lstore_1
02: aload_0
03: dup
04: astore 6
06: arraylength
07: istore 5
09: iconst_0
10: istore 4
12: goto 29
15: aload 6
17: iload 4
19: iaload
20: istore_3
21: lload_1
22: iload_3
23: i2l
24: ladd
25: lstore_1
26: iinc 4, 1
29: iload 4
31: iload 5
33: if_icmplt 15
0 array 4 0 (loop index)
1 0 (result) 5 array.length
2 - 6 array
3 array[index] 7 -
Loops – foreach II
static long loopForeachArray(int[] array) {
long result = 0;
for(int v : array) {
result += v;
}
return result;
}
00: lconst_0
01: lstore_1
02: aload_0
03: dup
04: astore 6
06: arraylength
07: istore 5
09: iconst_0
10: istore 4
12: goto 29
15: aload 6
17: iload 4
19: iaload
20: istore_3
21: lload_1
22: iload_3
23: i2l
24: ladd
25: lstore_1
26: iinc 4, 1
29: iload 4
31: iload 5
33: if_icmplt 15
0 array 4 0 (loop index)
1 0 + array[index] 5 array.length
2 - 6 array
3 array[index] 7 -
Loops – foreach II
static long loopForeachArray(int[] array) {
long result = 0;
for(int v : array) {
result += v;
}
return result;
}
00: lconst_0
01: lstore_1
02: aload_0
03: dup
04: astore 6
06: arraylength
07: istore 5
09: iconst_0
10: istore 4
12: goto 29
15: aload 6
17: iload 4
19: iaload
20: istore_3
21: lload_1
22: iload_3
23: i2l
24: ladd
25: lstore_1
26: iinc 4, 1
29: iload 4
31: iload 5
33: if_icmplt 15
0 array 4 0 (loop index) + 1
1 0 + array[index] 5 array.length
2 - 6 array
3 array[index] 7 -
→ 1,26% →
NOTASCALE
→ -18,33% →
Loops
Use arrays instead of lists
Manual bytecode
optimization
Worth it?
foreach loop 0: lconst_0
1: lstore_1
2: aload_0
3: dup
4: astore 6
6: arraylength
7: istore 5
9: iconst_0
10: istore 4
12: goto 29
15: aload 6
17: iload 4
19: iaload
20: istore_3
21: lload_1
22: iload_3
23: i2l
24: ladd
25: lstore_1
26: iinc 4, 1
29: iload 4
31: iload 5
33: if_icmplt 15
0: aload_0
1: arraylength
2: istore_3
3: iconst_0
4: istore_1
5: lconst_0
6: goto 17
9: aload_0
10: iload_1
11: iaload
12: i2l
13: ladd
14: iinc 1, 1
17: iload_1
18: iload_3
19: if_icmplt 9
Manual bytecode optimization
Manual bytecode optimization
0: aload_0
1: arraylength
2: istore_3
3: iconst_0
4: istore_1
5: lconst_0
6: goto 17
9: aload_0
10: iload_1
11: iaload
12: i2l
13: ladd
14: iinc 1, 1
17: iload_1
18: iload_3
19: if_icmplt 9
Local variables
0 array 3 -
1 - 4 -
2 - 5 -
Stack
-
-
-
0: aload_0
1: arraylength
2: istore_3
3: iconst_0
4: istore_1
5: lconst_0
6: goto 17
9: aload_0
10: iload_1
11: iaload
12: i2l
13: ladd
14: iinc 1, 1
17: iload_1
18: iload_3
19: if_icmplt 9
Local variables
0 array 3 array.length
1 - 4 -
2 - 5 -
Stack
-
-
-
Manual bytecode optimization
0: aload_0
1: arraylength
2: istore_3
3: iconst_0
4: istore_1
5: lconst_0
6: goto 17
9: aload_0
10: iload_1
11: iaload
12: i2l
13: ladd
14: iinc 1, 1
17: iload_1
18: iload_3
19: if_icmplt 9
Local variables
0 array 3 array.length
1 0 (index) 4 -
2 - 5 -
Stack
-
-
-
Manual bytecode optimization
0: aload_0
1: arraylength
2: istore_3
3: iconst_0
4: istore_1
5: lconst_0
6: goto 17
9: aload_0
10: iload_1
11: iaload
12: i2l
13: ladd
14: iinc 1, 1
17: iload_1
18: iload_3
19: if_icmplt 9
Local variables
0 array 3 array.length
1 0 (index) 4 -
2 - 5 -
Stack
0 (result)
-
-
Manual bytecode optimization
0: aload_0
1: arraylength
2: istore_3
3: iconst_0
4: istore_1
5: lconst_0
6: goto 17
9: aload_0
10: iload_1
11: iaload
12: i2l
13: ladd
14: iinc 1, 1
17: iload_1
18: iload_3
19: if_icmplt 9
Local variables
0 array 3 array.length
1 0 (index) 4 -
2 - 5 -
Stack
0 (result)
array[0]
-
Manual bytecode optimization
0: aload_0
1: arraylength
2: istore_3
3: iconst_0
4: istore_1
5: lconst_0
6: goto 17
9: aload_0
10: iload_1
11: iaload
12: i2l
13: ladd
14: iinc 1, 1
17: iload_1
18: iload_3
19: if_icmplt 9
Local variables
0 array 3 array.length
1 0 (index) 4 -
2 - 5 -
Stack
0 + array[0]
-
-
Manual bytecode optimization
0: aload_0
1: arraylength
2: istore_3
3: iconst_0
4: istore_1
5: lconst_0
6: goto 17
9: aload_0
10: iload_1
11: iaload
12: i2l
13: ladd
14: iinc 1, 1
17: iload_1
18: iload_3
19: if_icmplt 9
Local variables
0 array 3 array.length
1 0 (index) + 1 4 -
2 - 5 -
Stack
0 + array[0]
-
-
Manual bytecode optimization
0: aload_0
1: arraylength
2: istore_3
3: iconst_0
4: istore_1
5: lconst_0
6: goto 17
9: aload_0
10: iload_1
11: iaload
12: i2l
13: ladd
14: iinc 1, 1
17: iload_1
18: iload_3
19: if_icmplt 9
Local variables
0 array 3 array.length
1 1 (index) 4 -
2 - 5 -
Stack
0 + array[0]
-
-
Manual bytecode optimization
Worth it?
Only in very specific cases. And
then you’re probably using the
wrong language.
Too much effort involved…
But let D8/R8/Proguard do it for you!
Calling a method
Is there an overhead?
Overhead of calling a method
for(int i = 0; i < N; i++) {
setVal(getVal() + 1);
}
for(int i = 0; i < N; i++) {
val = val + 1;
}
vs
String concatenation
The evil + sign
String concatenation
String str = "";
for(int i = 0; i < N; i++) {
str += OTHER_STR;
}
String concatenation
String str = "";
for(int i = 0; i < N; i++) {
str += OTHER_STR;
}
0: ldc String
2: astore_1
3: iconst_0
4: istore_2
5: iload_2
6: sipush N
9: if_icmpge 40
12: new class java/lang/StringBuilder
15: dup
16: invokespecial java/lang/StringBuilder."<init>"
19: aload_1
20: invokevirtual java/lang/StringBuilder.append
23: aload_0
24: getfield OTHER_STR
27: invokevirtual java/lang/StringBuilder.append
30: invokevirtual java/lang/StringBuilder.toString
33: astore_1
34: iinc 2, 1
37: goto 5
String concatenation
String str = "";
for(int i = 0; i < N; i++) {
str += OTHER_STR;
}
0: ldc String
2: astore_1
3: iconst_0
4: istore_2
5: iload_2
6: sipush N
9: if_icmpge 40
12: new class java/lang/StringBuilder
15: dup
16: invokespecial java/lang/StringBuilder."<init>"
19: aload_1
20: invokevirtual java/lang/StringBuilder.append
23: aload_0
24: getfield OTHER_STR
27: invokevirtual java/lang/StringBuilder.append
30: invokevirtual java/lang/StringBuilder.toString
33: astore_1
34: iinc 2, 1
37: goto 5
String concatenation
String str = "";
for(int i = 0; i < N; i++) {
str += OTHER_STR;
}
0: ldc String
2: astore_1
3: iconst_0
4: istore_2
5: iload_2
6: sipush N
9: if_icmpge 40
12: new class java/lang/StringBuilder
15: dup
16: invokespecial java/lang/StringBuilder."<init>"
19: aload_1
20: invokevirtual java/lang/StringBuilder.append
23: aload_0
24: getfield OTHER_STR
27: invokevirtual java/lang/StringBuilder.append
30: invokevirtual java/lang/StringBuilder.toString
33: astore_1
34: iinc 2, 1
37: goto 5
String concatenation
String str = "";
for(int i = 0; i < N; i++) {
str += OTHER_STR;
}
0: ldc String
2: astore_1
3: iconst_0
4: istore_2
5: iload_2
6: sipush N
9: if_icmpge 40
12: new class java/lang/StringBuilder
15: dup
16: invokespecial java/lang/StringBuilder."<init>"
19: aload_1
20: invokevirtual java/lang/StringBuilder.append
23: aload_0
24: getfield OTHER_STR
27: invokevirtual java/lang/StringBuilder.append
30: invokevirtual java/lang/StringBuilder.toString
33: astore_1
34: iinc 2, 1
37: goto 5
String concatenation
String str = "";
for(int i = 0; i < N; i++) {
str += OTHER_STR;
}
0: ldc String
2: astore_1
3: iconst_0
4: istore_2
5: iload_2
6: sipush N
9: if_icmpge 40
12: new class java/lang/StringBuilder
15: dup
16: invokespecial java/lang/StringBuilder."<init>"
19: aload_1
20: invokevirtual java/lang/StringBuilder.append
23: aload_0
24: getfield OTHER_STR
27: invokevirtual java/lang/StringBuilder.append
30: invokevirtual java/lang/StringBuilder.toString
33: astore_1
34: iinc 2, 1
37: goto 5
String concatenation
String str = "";
for(int i = 0; i < N; i++) {
str += OTHER_STR;
}
0: ldc String
2: astore_1
3: iconst_0
4: istore_2
5: iload_2
6: sipush N
9: if_icmpge 40
12: new class java/lang/StringBuilder
15: dup
16: invokespecial java/lang/StringBuilder."<init>"
19: aload_1
20: invokevirtual java/lang/StringBuilder.append
23: aload_0
24: getfield OTHER_STR
27: invokevirtual java/lang/StringBuilder.append
30: invokevirtual java/lang/StringBuilder.toString
33: astore_1
34: iinc 2, 1
37: goto 5
String str = "";
for(int i = 0; i < N; i++) {
StringBuilder sb = new StringBuilder();
sb.append(str);
sb.append(OTHER_STR);
str = sb.toString();
}
String concatenation
Object creation:
String str = "";
for(int i = 0; i < N; i++) {
StringBuilder sb = new StringBuilder();
sb.append(str);
sb.append(OTHER_STR);
str = sb.toString();
}
String concatenation
String concatenation
alternatives
String.concat()
• Concat cost is O(N) + O(M)
• Concat returns a new String Object.
String str = "";
for(int i = 0; i < N; i++) {
str = str.concat(OTHER_STR);
}
String.concat()
Object creation:
String str = "";
for(int i = 0; i < N; i++) {
str = str.concat(OTHER_STR);
}
StringBuilder
• StringBuilder.append cost is O(M) [M being the
length of appended String]
StringBuilder sb = new StringBuilder()
for(int i = 0; i < N; i++) {
sb.append(OTHER_STR);
}
str = sb.toString();
StringBuilder
sb = new StringBuilder()
for(int i = 0; i < N; i++) {
sb.append(OTHER_STR);
}
str = sb.toString();
0: ldc String
2: astore_1
3: new java/lang/StringBuilder
6: dup
7: invokespecial java/lang/StringBuilder."<init>"
10: astore_2
11: iconst_0
12: istore_3
13: iload_3
14: sipush N
17: if_icmpge 35
20: aload_2
21: aload_0
22: getfield OTHER_STR
25: invokevirtual java/lang/StringBuilder.append
28: pop
29: iinc 3, 1
32: goto 13
0: ldc String
2: astore_1
3: new java/lang/StringBuilder
6: dup
7: invokespecial java/lang/StringBuilder."<init>"
10: astore_2
11: iconst_0
12: istore_3
13: iload_3
14: sipush N
17: if_icmpge 35
20: aload_2
21: aload_0
22: getfield OTHER_STR
25: invokevirtual java/lang/StringBuilder.append
28: pop
29: iinc 3, 1
32: goto 13
sb = new StringBuilder()
for(int i = 0; i < N; i++) {
sb.append(OTHER_STR);
}
str = sb.toString();
StringBuilder
Object creation:
StringBuilder sb = new StringBuilder();
for(int i = 0; i < N; i++) {
sb.append(OTHER_STR);
}
str = sb.toString();
StringBuilder
String concatenation
Use StringBuilder (properly) as
much as possible. StringBuffer
is the thread safe
implementation.
Strings in case statements
public void taskStateMachine(String status) {
switch(status) {
case "PENDING":
System.out.println("Status pending");
break;
case "EXECUTING":
System.out.println("Status executing");
break;
}
}
Code optimization example:
yuv2rgb converter.
Always measure!
Source: Wikipedia
Slightly optimized version
precalc tables, fixed point
operations, 2 pixels per loop…
Lets compare:
Normal, minified, minified
with optimizations & jack
Minified = obfuscated using Proguard
Normal Minified Minified & optimized Jack
0
2000
4000
6000
8000
10000
12000
14000
16000
18000
20000
non-optimized
optimized
Tooling
Tooling
Java
• javap -c <classfile>
Android:
•Dexdump -d <dexfile>
Tooling
D8/R8
https://android.googlesource.com/platform/external/r8/
Krakatau
https://github.com/Storyyeller/Krakatau
Tooling – Disassembler - ART
adb pull /data/dalvik-
cache/arm/data@app@<package>-
1@base apk@classes.dex
adb shell oatdump --oat-file=/data/dalvik-
cache/arm/data@app@<package>-
1@base.apk@classes.dex
Tooling – PrintAssembly - JIT
-XX:+UnlockDiagnosticVMOptions
-XX:+PrintAssembly
-XX:CompileCommand=print,com.raimon.test.Test::method
Under the Hood of the JVM: From Bytecode Through the
JIT to Assembly by @alblue
http://alblue.bandlem.com/2016/09/javaone-hotspot.html
Additional References
Sinking your teeth into bytecode by @jakewharton
http://jakewharton.com/sinking-your-teeth-into-bytecode/
Exploring Kotlin’s hidden costs by @BladeCoder
https://medium.com/@BladeCoder/exploring-kotlins-
hidden-costs-part-1-fbb9935d9b62
Performance measurements
Avoid doing multiple tests in one run
JIT might be evil!
Thank you!
http://blog.rafols.org
@rrafols
https://es.linkedin.com/in/raimonrafols

The bytecode gobbledygook

  • 1.
  • 2.
    Disclaimer: This presentation contains bytecode Contentis my own experimentation and might differ on other environments
  • 3.
    Competitions Work 2015 Local winner 2016+Ambassador 2016 Runner up 2018 Honorable mention Demoscene Speaker Author Entrepreneurship @rrafols
  • 4.
    Everything starts withour friend the java compiler.
  • 5.
    *.java → [javac]→ *.class
  • 6.
  • 7.
    *.java → [javac]→ *.class *.class → [dx] → dex file
  • 8.
    *.java → [javac]→ *.class *.class → [dx] → dex dex → [dexopt] → opt. dex dex → [dex2oat] → native
  • 9.
    but change iscoming! Jack & Jill
  • 10.
    but change iscoming! Jack & Jill
  • 11.
    *.java → [jack]→ dex file
  • 12.
    but change isstill coming! D8 & R8
  • 13.
    *.java → [javac]→ *.class *.class → [d8/r8] → dex file
  • 14.
    Let’s focus firston javac Javac vs other compilers
  • 15.
  • 16.
  • 17.
    javac Does not knowon which architecture the code will be executed
  • 18.
  • 19.
    For this reason Javabytecode & operations are stack based
  • 20.
    Easy to interpret Butnot the most performant solution
  • 21.
    Quick example Stack basedinteger addition
  • 22.
    j = j+ i
  • 23.
  • 24.
  • 25.
  • 26.
    add r01, r02,r01 or add eax, ebx
  • 27.
    Let’s make things interesting… j= j + i + k + w + h * 2 + p * p;
  • 28.
  • 29.
    0: iload_2 1: iload_1 2:iadd 3: iload_3 4: iadd 5: iload 4 7: iadd 8: iload 5 10: iconst_2 11: imul 12: iadd 13: iload 6 15: iload 6 17: imul 18: iadd 19: istore_2 j = j + i + k + w + h * 2 + p * p; Local vars 1: i 2: j 3: k 4: w 5: h 6: p
  • 30.
    0: iload_2 1: iload_1 2:iadd 3: iload_3 4: iadd 5: iload 4 7: iadd 8: iload 5 10: iconst_2 11: imul 12: iadd 13: iload 6 15: iload 6 17: imul 18: iadd 19: istore_2 j = j + i + k + w + h * 2 + p * p; Local vars 1: i 2: j 3: k 4: w 5: h 6: p
  • 31.
    0: iload_2 1: iload_1 2:iadd 3: iload_3 4: iadd 5: iload 4 7: iadd 8: iload 5 10: iconst_2 11: imul 12: iadd 13: iload 6 15: iload 6 17: imul 18: iadd 19: istore_2 j = j + i + k + w + h * 2 + p * p; Local vars 1: i 2: j 3: k 4: w 5: h 6: p
  • 32.
    0: iload_2 1: iload_1 2:iadd 3: iload_3 4: iadd 5: iload 4 7: iadd 8: iload 5 10: iconst_2 11: imul 12: iadd 13: iload 6 15: iload 6 17: imul 18: iadd 19: istore_2 j = j + i + k + w + h * 2 + p * p; Local vars 1: i 2: j 3: k 4: w 5: h 6: p
  • 33.
    0: iload_2 1: iload_1 2:iadd 3: iload_3 4: iadd 5: iload 4 7: iadd 8: iload 5 10: iconst_2 11: imul 12: iadd 13: iload 6 15: iload 6 17: imul 18: iadd 19: istore_2 j = j + i + k + w + h * 2 + p * p; Local vars 1: i 2: j 3: k 4: w 5: h 6: p
  • 34.
    0: iload_2 1: iload_1 2:iadd 3: iload_3 4: iadd 5: iload 4 7: iadd 8: iload 5 10: iconst_2 11: imul 12: iadd 13: iload 6 15: iload 6 17: imul 18: iadd 19: istore_2 j = j + i + k + w + h * 2 + p * p; Local vars 1: i 2: j 3: k 4: w 5: h 6: p
  • 35.
    0: iload_2 1: iload_1 2:iadd 3: iload_3 4: iadd 5: iload 4 7: iadd 8: iload 5 10: iconst_2 11: imul 12: iadd 13: iload 6 15: iload 6 17: imul 18: iadd 19: istore_2 j = j + i + k + w + h * 2 + p * p; Local vars 1: i 2: j 3: k 4: w 5: h 6: p
  • 36.
  • 37.
    add r01, r02,r01 add r01, r03, r01 add r01, r04, r01 mul r07, r05, #2 add r01, r07, r01 mul r08, r06, r06 add r02, r08, r01 j = j + i + k + w + h * 2 + p * p; r01: i r02: j r03: k r04: w r05: h r06: p
  • 38.
    Java VM (JVM) Onlythe JVM knows the architecture where is running. In our previous example, we used up to 8 registers, but some CPUs might have less than 8 registers…
  • 39.
    Java VM (JVM) Alloptimizations are left to be done by the JVM
  • 40.
    Maybe takes thisconcept a bit too far...
  • 41.
    Imagine this simpleC code #include <stdio.h> int main() { int a = 10; int b = 1 + 2 + 3 + 4 + 5 + 6 + a; printf("%dn", b); }
  • 42.
    GCC compiler #include <stdio.h> intmain() { int a = 10; int b = 1 + 2 + 3 + 4 + 5 + 6 + a; printf("%dn", b); } … movl $31, %esi call _printf … * Using gcc & -O2 compiler option
  • 43.
    javac public static voidmain(String args[]) { int a = 10; int b = 1 + 2 + 3 + 4 + 5 + 6 + a; System.out.println(b); } 0: bipush 10 2: istore_1 3: bipush 21 5: iload_1 6: iadd 7: istore_2 ...
  • 44.
    Let's do asmall change #include <stdio.h> int main() { int a = 10; int b = 1 + 2 + 3 + 4 + 5 + a + 6; printf("%dn", b); }
  • 45.
    GCC compiler #include <stdio.h> intmain() { int a = 10; int b = 1 + 2 + 3 + 4 + 5 + a + 6; printf("%dn", b); } … movl $31, %esi call _printf … * Using gcc & -O2 compiler option
  • 46.
    javac public static voidmain(String args[]) { int a = 10; int b = 1 + 2 + 3 + 4 + 5 + a + 6; System.out.println(b); } 0: bipush 10 2: istore_1 3: bipush 15 5: iload_1 6: iadd 7: bipush 6 9: iadd 10: istore_2
  • 47.
    Let's do anotherquick change.. public static void main(String args[]) { int a = 10; int b = a + 1 + 2 + 3 + 4 + 5 + 6; System.out.println(b); }
  • 48.
    javac 00: bipush 10 02:istore_1 03: iload_1 04: iconst_1 05: iadd 06: iconst_2 07: iadd 08: iconst_3 09: iadd 10: iconst_4 11: iadd 12: iconst_5 13: iadd 14: bipush 6 16: iadd 17: istore_2 public static void main(String args[]) { int a = 10; int b = a + 1 + 2 + 3 + 4 + 5 + 6; System.out.println(b); }
  • 49.
    On Android therewas jack to the rescue...
  • 50.
    jack public static voidmain(String args[]) { int a = 10; int b = a + 1 + 2 + 3 + 4 + 5 + 6; System.out.println(b); } ... 0: const/16 v0, #int 31 2: sget-object v1, Ljava/lang/System; 4: invoke-virtual {v1, v0} 7: return-void ...
  • 51.
    but d8 doesthe job as well...
  • 52.
    d8 public static voidmain(String args[]) { int a = 10; int b = a + 1 + 2 + 3 + 4 + 5 + 6; System.out.println(b); } ... 0: sget-object v1, Ljava/lang/System;… 2: const/16 v0, #int 31 4: invoke-virtual {v1, v0} 7: return-void ...
  • 53.
    And on Javathere is the JIT compiler to the rescue
  • 54.
    JIT assembly output publicstatic void main(String args[]) { int a = 10; int b = a + 1 + 2 + 3 + 4 + 5 + 6; System.out.println(b); } ... 0x00000001104b2bff: mov eax, 0x0001f ... 0: bipush 10 2: istore_1 3: iload_1 4: iconst_1 5: iadd 6: iconst_2 7: iadd 8: iconst_3 9: iadd 10: iconst_4 11: iadd 12: iconst_5 13: iadd 14: bipush 6 16: iadd 17: istore_2
  • 55.
  • 56.
    Autoboxing Transparent to thedeveloper but compiler adds some 'extra' code
  • 57.
    Autoboxing long total =0; for(int i = 0; i < N; i++) { total += i; } 0: lconst_0 1: lstore_1 2: iconst_0 3: istore_3 4: iload_3 5: ldc #8 // N 7: if_icmpge 21 10: lload_1 11: iload_3 12: i2l 13: ladd 14: lstore_1 15: iinc 3, 1 18: goto 4
  • 58.
    Autoboxing long total =0; for(int i = 0; i < N; i++) { total += i; } 0: lconst_0 1: lstore_1 2: iconst_0 3: istore_3 4: iload_3 5: ldc #8 // N 7: if_icmpge 21 10: lload_1 11: iload_3 12: i2l 13: ladd 14: lstore_1 15: iinc 3, 1 18: goto 4
  • 59.
    Autoboxing long total =0; for(int i = 0; i < N; i++) { total += i; } 0: lconst_0 1: lstore_1 2: iconst_0 3: istore_3 4: iload_3 5: ldc #8 // N 7: if_icmpge 21 10: lload_1 11: iload_3 12: i2l 13: ladd 14: lstore_1 15: iinc 3, 1 18: goto 4
  • 60.
    Autoboxing long total =0; for(int i = 0; i < N; i++) { total += i; } 0: lconst_0 1: lstore_1 2: iconst_0 3: istore_3 4: iload_3 5: ldc #8 // N 7: if_icmpge 21 10: lload_1 11: iload_3 12: i2l 13: ladd 14: lstore_1 15: iinc 3, 1 18: goto 4 21:
  • 61.
    Autoboxing long total =0; for(int i = 0; i < N; i++) { total += i; } 0: lconst_0 1: lstore_1 2: iconst_0 3: istore_3 4: iload_3 5: ldc #8 // N 7: if_icmpge 21 10: lload_1 11: iload_3 12: i2l 13: ladd 14: lstore_1 15: iinc 3, 1 18: goto 4
  • 62.
    Autoboxing long total =0; for(int i = 0; i < N; i++) { total += i; } 0: lconst_0 1: lstore_1 2: iconst_0 3: istore_3 4: iload_3 5: ldc #8 // N 7: if_icmpge 21 10: lload_1 11: iload_3 12: i2l 13: ladd 14: lstore_1 15: iinc 3, 1 18: goto 4
  • 63.
    Autoboxing long total =0; for(int i = 0; i < N; i++) { total += i; } 0: lconst_0 1: lstore_1 2: iconst_0 3: istore_3 4: iload_3 5: ldc #8 // N 7: if_icmpge 21 10: lload_1 11: iload_3 12: i2l 13: ladd 14: lstore_1 15: iinc 3, 1 18: goto 4
  • 64.
    Autoboxing Long total =0; for(Integer i = 0; i < N; i++) { total += i; }
  • 65.
    Autoboxing Long total =0; for(Integer i = 0; i < N; i++) { total += i; } 00: lconst_0 01: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la 04: astore_1 05: iconst_0 06: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/ 09: astore_2 10: aload_2 11: invokevirtual #9 // java/lang/Integer.intValue:()I 14: sipush N 17: if_icmpge 54 20: aload_1 21: invokevirtual #10 // java/lang/Long.longValue:()J 24: aload_2 25: invokevirtual #9 // java/lang/Integer.intValue:()I 28: i2l 29: ladd 30: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la 33: astore_1 34: aload_2 35: astore_3 36: aload_2 37: invokevirtual #9 // java/lang/Integer.intValue:()I 40: iconst_1 41: iadd 42: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/ 45: dup 46: astore_2 47: astore 4 49: aload_3 50: pop 51: goto 10
  • 66.
    Autoboxing Long total =0; for(Integer i = 0; i < N; i++) { total += i; } 00: lconst_0 01: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la 04: astore_1 05: iconst_0 06: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/ 09: astore_2 10: aload_2 11: invokevirtual #9 // java/lang/Integer.intValue:()I 14: sipush N 17: if_icmpge 54 20: aload_1 21: invokevirtual #10 // java/lang/Long.longValue:()J 24: aload_2 25: invokevirtual #9 // java/lang/Integer.intValue:()I 28: i2l 29: ladd 30: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la 33: astore_1 34: aload_2 35: astore_3 36: aload_2 37: invokevirtual #9 // java/lang/Integer.intValue:()I 40: iconst_1 41: iadd 42: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/ 45: dup 46: astore_2 47: astore 4 49: aload_3 50: pop 51: goto 10
  • 67.
    Autoboxing Long total =0; for(Integer i = 0; i < N; i++) { total += i; } 00: lconst_0 01: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la 04: astore_1 05: iconst_0 06: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/ 09: astore_2 10: aload_2 11: invokevirtual #9 // java/lang/Integer.intValue:()I 14: sipush N 17: if_icmpge 54 20: aload_1 21: invokevirtual #10 // java/lang/Long.longValue:()J 24: aload_2 25: invokevirtual #9 // java/lang/Integer.intValue:()I 28: i2l 29: ladd 30: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la 33: astore_1 34: aload_2 35: astore_3 36: aload_2 37: invokevirtual #9 // java/lang/Integer.intValue:()I 40: iconst_1 41: iadd 42: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/ 45: dup 46: astore_2 47: astore 4 49: aload_3 50: pop 51: goto 10
  • 68.
    Autoboxing Long total =0; for(Integer i = 0; i < N; i++) { total += i; } 00: lconst_0 01: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la 04: astore_1 05: iconst_0 06: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/ 09: astore_2 10: aload_2 11: invokevirtual #9 // java/lang/Integer.intValue:()I 14: sipush N 17: if_icmpge 54 20: aload_1 21: invokevirtual #10 // java/lang/Long.longValue:()J 24: aload_2 25: invokevirtual #9 // java/lang/Integer.intValue:()I 28: i2l 29: ladd 30: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la 33: astore_1 34: aload_2 35: astore_3 36: aload_2 37: invokevirtual #9 // java/lang/Integer.intValue:()I 40: iconst_1 41: iadd 42: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/ 45: dup 46: astore_2 47: astore 4 49: aload_3 50: pop 51: goto 10
  • 69.
    Autoboxing Long total =0; for(Integer i = 0; i < N; i++) { total += i; } 00: lconst_0 01: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la 04: astore_1 05: iconst_0 06: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/ 09: astore_2 10: aload_2 11: invokevirtual #9 // java/lang/Integer.intValue:()I 14: sipush N 17: if_icmpge 54 20: aload_1 21: invokevirtual #10 // java/lang/Long.longValue:()J 24: aload_2 25: invokevirtual #9 // java/lang/Integer.intValue:()I 28: i2l 29: ladd 30: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la 33: astore_1 34: aload_2 35: astore_3 36: aload_2 37: invokevirtual #9 // java/lang/Integer.intValue:()I 40: iconst_1 41: iadd 42: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/ 45: dup 46: astore_2 47: astore 4 49: aload_3 50: pop 51: goto 10
  • 70.
    Autoboxing Long total =0; for(Integer i = 0; i < N; i++) { total += i; } 00: lconst_0 01: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la 04: astore_1 05: iconst_0 06: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/ 09: astore_2 10: aload_2 11: invokevirtual #9 // java/lang/Integer.intValue:()I 14: sipush N 17: if_icmpge 54 20: aload_1 21: invokevirtual #10 // java/lang/Long.longValue:()J 24: aload_2 25: invokevirtual #9 // java/lang/Integer.intValue:()I 28: i2l 29: ladd 30: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la 33: astore_1 34: aload_2 35: astore_3 36: aload_2 37: invokevirtual #9 // java/lang/Integer.intValue:()I 40: iconst_1 41: iadd 42: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/ 45: dup 46: astore_2 47: astore 4 49: aload_3 50: pop 51: goto 10
  • 71.
    Autoboxing Long total =0; for(Integer i = 0; i < N; i++) { total += i; } 00: lconst_0 01: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la 04: astore_1 05: iconst_0 06: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/ 09: astore_2 10: aload_2 11: invokevirtual #9 // java/lang/Integer.intValue:()I 14: sipush N 17: if_icmpge 54 20: aload_1 21: invokevirtual #10 // java/lang/Long.longValue:()J 24: aload_2 25: invokevirtual #9 // java/lang/Integer.intValue:()I 28: i2l 29: ladd 30: invokestatic #7 // java/lang/Long.valueOf:(J)Ljava/la 33: astore_1 34: aload_2 35: astore_3 36: aload_2 37: invokevirtual #9 // java/lang/Integer.intValue:()I 40: iconst_1 41: iadd 42: invokestatic #8 // java/lang/Integer.valueOf:(I)Ljava/ 45: dup 46: astore_2 47: astore 4 49: aload_3 50: pop 51: goto 10
  • 72.
    Autoboxing Long total =0; for(Integer i = 0; i < N; i++) { total += i; } // ? 00: lconst_0 01: invokestatic #7 // Method java/lang/Long.valueOf:(J)L 04: astore_1 05: iconst_0 06: invokestatic #8 // Method java/lang/Integer.valueOf:(I 09: astore_2 10: aload_2 11: invokevirtual #9 // Method java/lang/Integer.intValue: 14: sipush N 17: if_icmpge 54 20: aload_1 21: invokevirtual #10 // Method java/lang/Long.longValue:( 24: aload_2 25: invokevirtual #9 // Method java/lang/Integer.intValue: 28: i2l 29: ladd 30: invokestatic #7 // Method java/lang/Long.valueOf:(J)L 33: astore_1 34: aload_2 35: astore_3 36: aload_2 37: invokevirtual #9 // Method java/lang/Integer.intValue: 40: iconst_1 41: iadd 42: invokestatic #8 // Method java/lang/Integer.valueOf:(I 45: dup 46: astore_2 47: astore 4 49: aload_3 50: pop 51: goto 10
  • 73.
    Autoboxing This is whatthat code is actually doing: Long total = Long.valueOf(0); for(Integer i = Integer.valueOf(0); i.intValue() < N; i = Integer.valueOf(i.intValue() + 1)) { total = Long.valueOf(total.longValue() + (long)i.intValue()) }
  • 74.
    Autoboxing Object creation Long total= Long.valueOf(0); for(Integer i = Integer.valueOf(0); i.intValue() < N; i = Integer.valueOf(i.intValue() + 1)) { total = Long.valueOf(total.longValue() + (long)i.intValue()) }
  • 75.
  • 76.
    Autoboxing D8 does nothelp in this situation (neither Jack)
  • 77.
    Autoboxing What about theJIT compiler on plain java?
  • 78.
    Autoboxing Let's run thatloop N times (on my desktop computer) N = 10.000.000.000
  • 79.
  • 80.
    Autoboxing Let’s try iton Android Dalvik VM & ART
  • 81.
  • 82.
  • 83.
  • 84.
    Let's sort somenumbers… Arrays.sort(...)
  • 85.
    Difference between sorting primitivetypes (int) & objects (Integer)
  • 86.
    Using int &Integer
  • 87.
    When sorting objectsjava uses a stable sort Default java algorithm: TimSort adaptation
  • 88.
    Sorting primitives doesnot require to be stable sort Default java algorithm: Dual-Pivot quicksort
  • 89.
    Sorting Use primitive typesas much as possible
  • 90.
    Loops What is goingon behind the scenes
  • 91.
    Loops - List ArrayList<Integer>list = new … static long loopStandardList() { long result = 0; for(int i = 0; i < list.size(); i++) { result += list.get(i); } return result; }
  • 92.
    ArrayList<Integer> list =new … static long loopStandardList() { long result = 0; for(int i = 0; i < list.size(); i++) { result += list.get(i); } return result; } 07: lload_0 08: getstatic list 11: iload_2 12: invokevirtual java/util/ArrayList.get 15: checkcast java/lang/Integer 18: invokevirtual java/lang/Integer.intValue 21: i2l 22: ladd 23: lstore_0 24: iinc 2, 1 27: iload_2 28: getstatic list 31: invokevirtual java/util/ArrayList.size 34: if_icmplt 7 Loops - List
  • 93.
    ArrayList<Integer> list =new … static long loopStandardList() { long result = 0; for(int i = 0; i < list.size(); i++) { result += list.get(i); } return result; } Loops - List 07: lload_0 08: getstatic list 11: iload_2 12: invokevirtual java/util/ArrayList.get 15: checkcast java/lang/Integer 18: invokevirtual java/lang/Integer.intValue 21: i2l 22: ladd 23: lstore_0 24: iinc 2, 1 27: iload_2 28: getstatic list 31: invokevirtual java/util/ArrayList.size 34: if_icmplt 7
  • 94.
    ArrayList<Integer> list =new … static long loopStandardList() { long result = 0; for(int i = 0; i < list.size(); i++) { result += list.get(i); } return result; } Loops - List 07: lload_0 08: getstatic list 11: iload_2 12: invokevirtual java/util/ArrayList.get 15: checkcast java/lang/Integer 18: invokevirtual java/lang/Integer.intValue 21: i2l 22: ladd 23: lstore_0 24: iinc 2, 1 27: iload_2 28: getstatic list 31: invokevirtual java/util/ArrayList.size 34: if_icmplt 7
  • 95.
    ArrayList<Integer> list =new … static long loopStandardList() { long result = 0; for(int i = 0; i < list.size(); i++) { result += list.get(i); } return result; } Loops - List 07: lload_0 08: getstatic list 11: iload_2 12: invokevirtual java/util/ArrayList.get 15: checkcast java/lang/Integer 18: invokevirtual java/lang/Integer.intValue 21: i2l 22: ladd 23: lstore_0 24: iinc 2, 1 27: iload_2 28: getstatic list 31: invokevirtual java/util/ArrayList.size 34: if_icmplt 7
  • 96.
    Loops - foreach ArrayList<Integer>list = new … static long loopForeachList() { long result = 0; for(int v : list) { result += v; } return result; }
  • 97.
    ArrayList<Integer> list =new … static long loopForeachList() { long result = 0; for(int v : list) { result += v; } return result; } 12: aload_3 13: invokeinterface java/util/Iterator.next 18: checkcast java/lang/Integer 21: invokevirtual java/lang/Integer.intValue 24: istore_2 25: lload_0 26: iload_2 27: i2l 28: ladd 29: lstore_0 30: aload_3 31: invokeinterface java/util/Iterator.hasNext 36: ifne 12 Loops - foreach
  • 98.
    ArrayList<Integer> list =new … static long loopForeachList() { long result = 0; for(int v : list) { result += v; } return result; } Loops - foreach 12: aload_3 13: invokeinterface java/util/Iterator.next 18: checkcast java/lang/Integer 21: invokevirtual java/lang/Integer.intValue 24: istore_2 25: lload_0 26: iload_2 27: i2l 28: ladd 29: lstore_0 30: aload_3 31: invokeinterface java/util/Iterator.hasNext 36: ifne 12
  • 99.
    ArrayList<Integer> list =new … static long loopForeachList() { long result = 0; for(int v : list) { result += v; } return result; } Loops - foreach 12: aload_3 13: invokeinterface java/util/Iterator.next 18: checkcast java/lang/Integer 21: invokevirtual java/lang/Integer.intValue 24: istore_2 25: lload_0 26: iload_2 27: i2l 28: ladd 29: lstore_0 30: aload_3 31: invokeinterface java/util/Iterator.hasNext 36: ifne 12
  • 100.
    Loops - Array staticint[] array = new ... static long loopStandardArray() { long result = 0; for(int i = 0; i < array.length; i++) { result += array[i]; } return result; }
  • 101.
    static int[] array= new ... static long loopStandardArray() { long result = 0; for(int i = 0; i < array.length; i++) { result += array[i]; } return result; } 07: lload_0 08: getstatic array 11: iload_2 12: iaload 13: i2l 14: ladd 15: lstore_0 16: iinc 2, 1 19: iload_2 20: getstatic array 23: arraylength 24: if_icmplt 7 Loops - Array
  • 102.
    static int[] array= new ... static long loopStandardArray() { long result = 0; for(int i = 0; i < array.length; i++) { result += array[i]; } return result; } Loops - Array 07: lload_0 08: getstatic array 11: iload_2 12: iaload 13: i2l 14: ladd 15: lstore_0 16: iinc 2, 1 19: iload_2 20: getstatic array 23: arraylength 24: if_icmplt 7
  • 103.
    static int[] array= new ... static long loopStandardArray() { long result = 0; for(int i = 0; i < array.length; i++) { result += array[i]; } return result; } Loops - Array 07: lload_0 08: getstatic array 11: iload_2 12: iaload 13: i2l 14: ladd 15: lstore_0 16: iinc 2, 1 19: iload_2 20: getstatic array 23: arraylength 24: if_icmplt 7
  • 104.
    Loops - sizecached static int[] array = new ... static long loopStandardArray () { long result = 0; int length = array.length; for(int i = 0; i < length; i++) { result += array[i]; } return result; }
  • 105.
    static int[] array= new ... static long loopStandardArray () { long result = 0; int length = array.length; for(int i = 0; i < length; i++) { result += array[i]; } return result; } 12: lload_0 13: getstatic array 16: iload_3 17: iaload 18: i2l 19: ladd 20: lstore_0 21: iinc 3, 1 24: iload_3 25: iload_2 26: if_icmplt 12 Loops - size cached
  • 106.
    static int[] array= new ... static long loopStandardArray () { long result = 0; int length = array.length; for(int i = 0; i < length; i++) { result += array[i]; } return result; } Loops - size cached 12: lload_0 13: getstatic array 16: iload_3 17: iaload 18: i2l 19: ladd 20: lstore_0 21: iinc 3, 1 24: iload_3 25: iload_2 26: if_icmplt 12
  • 107.
    Loops - backwards staticint[] array = new ... static long loopStandardArray () { long result = 0; for(int i = array.length - 1; i >= 0; i--) { result += array[i]; } return result; }
  • 108.
    static int[] array= new ... static long loopStandardArray () { long result = 0; for(int i = array.length - 1; i >= 0; i--) { result += array[i]; } return result; } 12: lload_0 13: getstatic array 16: iload_2 17: iaload 18: i2l 19: ladd 20: lstore_0 21: iinc 2, -1 24: iload_2 25: ifge 12 Loops - backwards
  • 109.
    static int[] array= new ... static long loopStandardArray () { long result = 0; for(int i = array.length - 1; i >= 0; i--) { result += array[i]; } return result; } Loops - backwards 12: lload_0 13: getstatic array 16: iload_2 17: iaload 18: i2l 19: ladd 20: lstore_0 21: iinc 2, -1 24: iload_2 25: ifge 12
  • 112.
  • 113.
    Loops – foreachII static long loopForeachArray(int[] array) { long result = 0; for(int v : array) { result += v; } return result; }
  • 114.
    Loops – foreachII static long loopForeachArray(int[] array) { long result = 0; for(int v : array) { result += v; } return result; } 00: lconst_0 01: lstore_1 02: aload_0 03: dup 04: astore 6 06: arraylength 07: istore 5 09: iconst_0 10: istore 4 12: goto 29 15: aload 6 17: iload 4 19: iaload 20: istore_3 21: lload_1 22: iload_3 23: i2l 24: ladd 25: lstore_1 26: iinc 4, 1 29: iload 4 31: iload 5 33: if_icmplt 15 0 array 4 - 1 - 5 - 2 - 6 - 3 - 7 -
  • 115.
    Loops – foreachII static long loopForeachArray(int[] array) { long result = 0; for(int v : array) { result += v; } return result; } 00: lconst_0 01: lstore_1 02: aload_0 03: dup 04: astore 6 06: arraylength 07: istore 5 09: iconst_0 10: istore 4 12: goto 29 15: aload 6 17: iload 4 19: iaload 20: istore_3 21: lload_1 22: iload_3 23: i2l 24: ladd 25: lstore_1 26: iinc 4, 1 29: iload 4 31: iload 5 33: if_icmplt 15 0 array 4 - 1 0 (result) 5 - 2 - 6 - 3 - 7 -
  • 116.
    Loops – foreachII static long loopForeachArray(int[] array) { long result = 0; for(int v : array) { result += v; } return result; } 00: lconst_0 01: lstore_1 02: aload_0 03: dup 04: astore 6 06: arraylength 07: istore 5 09: iconst_0 10: istore 4 12: goto 29 15: aload 6 17: iload 4 19: iaload 20: istore_3 21: lload_1 22: iload_3 23: i2l 24: ladd 25: lstore_1 26: iinc 4, 1 29: iload 4 31: iload 5 33: if_icmplt 15 0 array 4 - 1 0 (result) 5 - 2 - 6 array 3 - 7 -
  • 117.
    Loops – foreachII static long loopForeachArray(int[] array) { long result = 0; for(int v : array) { result += v; } return result; } 00: lconst_0 01: lstore_1 02: aload_0 03: dup 04: astore 6 06: arraylength 07: istore 5 09: iconst_0 10: istore 4 12: goto 29 15: aload 6 17: iload 4 19: iaload 20: istore_3 21: lload_1 22: iload_3 23: i2l 24: ladd 25: lstore_1 26: iinc 4, 1 29: iload 4 31: iload 5 33: if_icmplt 15 0 array 4 - 1 0 (result) 5 array.length 2 - 6 array 3 - 7 -
  • 118.
    Loops – foreachII static long loopForeachArray(int[] array) { long result = 0; for(int v : array) { result += v; } return result; } 00: lconst_0 01: lstore_1 02: aload_0 03: dup 04: astore 6 06: arraylength 07: istore 5 09: iconst_0 10: istore 4 12: goto 29 15: aload 6 17: iload 4 19: iaload 20: istore_3 21: lload_1 22: iload_3 23: i2l 24: ladd 25: lstore_1 26: iinc 4, 1 29: iload 4 31: iload 5 33: if_icmplt 15 0 array 4 0 (loop index) 1 0 (result) 5 array.length 2 - 6 array 3 - 7 -
  • 119.
    Loops – foreachII static long loopForeachArray(int[] array) { long result = 0; for(int v : array) { result += v; } return result; } 00: lconst_0 01: lstore_1 02: aload_0 03: dup 04: astore 6 06: arraylength 07: istore 5 09: iconst_0 10: istore 4 12: goto 29 15: aload 6 17: iload 4 19: iaload 20: istore_3 21: lload_1 22: iload_3 23: i2l 24: ladd 25: lstore_1 26: iinc 4, 1 29: iload 4 31: iload 5 33: if_icmplt 15 0 array 4 0 (loop index) 1 0 (result) 5 array.length 2 - 6 array 3 - 7 -
  • 120.
    Loops – foreachII static long loopForeachArray(int[] array) { long result = 0; for(int v : array) { result += v; } return result; } 00: lconst_0 01: lstore_1 02: aload_0 03: dup 04: astore 6 06: arraylength 07: istore 5 09: iconst_0 10: istore 4 12: goto 29 15: aload 6 17: iload 4 19: iaload 20: istore_3 21: lload_1 22: iload_3 23: i2l 24: ladd 25: lstore_1 26: iinc 4, 1 29: iload 4 31: iload 5 33: if_icmplt 15 0 array 4 0 (loop index) 1 0 (result) 5 array.length 2 - 6 array 3 array[index] 7 -
  • 121.
    Loops – foreachII static long loopForeachArray(int[] array) { long result = 0; for(int v : array) { result += v; } return result; } 00: lconst_0 01: lstore_1 02: aload_0 03: dup 04: astore 6 06: arraylength 07: istore 5 09: iconst_0 10: istore 4 12: goto 29 15: aload 6 17: iload 4 19: iaload 20: istore_3 21: lload_1 22: iload_3 23: i2l 24: ladd 25: lstore_1 26: iinc 4, 1 29: iload 4 31: iload 5 33: if_icmplt 15 0 array 4 0 (loop index) 1 0 + array[index] 5 array.length 2 - 6 array 3 array[index] 7 -
  • 122.
    Loops – foreachII static long loopForeachArray(int[] array) { long result = 0; for(int v : array) { result += v; } return result; } 00: lconst_0 01: lstore_1 02: aload_0 03: dup 04: astore 6 06: arraylength 07: istore 5 09: iconst_0 10: istore 4 12: goto 29 15: aload 6 17: iload 4 19: iaload 20: istore_3 21: lload_1 22: iload_3 23: i2l 24: ladd 25: lstore_1 26: iinc 4, 1 29: iload 4 31: iload 5 33: if_icmplt 15 0 array 4 0 (loop index) + 1 1 0 + array[index] 5 array.length 2 - 6 array 3 array[index] 7 -
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
    foreach loop 0:lconst_0 1: lstore_1 2: aload_0 3: dup 4: astore 6 6: arraylength 7: istore 5 9: iconst_0 10: istore 4 12: goto 29 15: aload 6 17: iload 4 19: iaload 20: istore_3 21: lload_1 22: iload_3 23: i2l 24: ladd 25: lstore_1 26: iinc 4, 1 29: iload 4 31: iload 5 33: if_icmplt 15 0: aload_0 1: arraylength 2: istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_0 10: iload_1 11: iaload 12: i2l 13: ladd 14: iinc 1, 1 17: iload_1 18: iload_3 19: if_icmplt 9 Manual bytecode optimization
  • 128.
    Manual bytecode optimization 0:aload_0 1: arraylength 2: istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_0 10: iload_1 11: iaload 12: i2l 13: ladd 14: iinc 1, 1 17: iload_1 18: iload_3 19: if_icmplt 9 Local variables 0 array 3 - 1 - 4 - 2 - 5 - Stack - - -
  • 129.
    0: aload_0 1: arraylength 2:istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_0 10: iload_1 11: iaload 12: i2l 13: ladd 14: iinc 1, 1 17: iload_1 18: iload_3 19: if_icmplt 9 Local variables 0 array 3 array.length 1 - 4 - 2 - 5 - Stack - - - Manual bytecode optimization
  • 130.
    0: aload_0 1: arraylength 2:istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_0 10: iload_1 11: iaload 12: i2l 13: ladd 14: iinc 1, 1 17: iload_1 18: iload_3 19: if_icmplt 9 Local variables 0 array 3 array.length 1 0 (index) 4 - 2 - 5 - Stack - - - Manual bytecode optimization
  • 131.
    0: aload_0 1: arraylength 2:istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_0 10: iload_1 11: iaload 12: i2l 13: ladd 14: iinc 1, 1 17: iload_1 18: iload_3 19: if_icmplt 9 Local variables 0 array 3 array.length 1 0 (index) 4 - 2 - 5 - Stack 0 (result) - - Manual bytecode optimization
  • 132.
    0: aload_0 1: arraylength 2:istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_0 10: iload_1 11: iaload 12: i2l 13: ladd 14: iinc 1, 1 17: iload_1 18: iload_3 19: if_icmplt 9 Local variables 0 array 3 array.length 1 0 (index) 4 - 2 - 5 - Stack 0 (result) array[0] - Manual bytecode optimization
  • 133.
    0: aload_0 1: arraylength 2:istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_0 10: iload_1 11: iaload 12: i2l 13: ladd 14: iinc 1, 1 17: iload_1 18: iload_3 19: if_icmplt 9 Local variables 0 array 3 array.length 1 0 (index) 4 - 2 - 5 - Stack 0 + array[0] - - Manual bytecode optimization
  • 134.
    0: aload_0 1: arraylength 2:istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_0 10: iload_1 11: iaload 12: i2l 13: ladd 14: iinc 1, 1 17: iload_1 18: iload_3 19: if_icmplt 9 Local variables 0 array 3 array.length 1 0 (index) + 1 4 - 2 - 5 - Stack 0 + array[0] - - Manual bytecode optimization
  • 135.
    0: aload_0 1: arraylength 2:istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_0 10: iload_1 11: iaload 12: i2l 13: ladd 14: iinc 1, 1 17: iload_1 18: iload_3 19: if_icmplt 9 Local variables 0 array 3 array.length 1 1 (index) 4 - 2 - 5 - Stack 0 + array[0] - - Manual bytecode optimization
  • 137.
    Worth it? Only invery specific cases. And then you’re probably using the wrong language. Too much effort involved… But let D8/R8/Proguard do it for you!
  • 138.
    Calling a method Isthere an overhead?
  • 139.
    Overhead of callinga method for(int i = 0; i < N; i++) { setVal(getVal() + 1); } for(int i = 0; i < N; i++) { val = val + 1; } vs
  • 141.
  • 142.
    String concatenation String str= ""; for(int i = 0; i < N; i++) { str += OTHER_STR; }
  • 143.
    String concatenation String str= ""; for(int i = 0; i < N; i++) { str += OTHER_STR; } 0: ldc String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: sipush N 9: if_icmpge 40 12: new class java/lang/StringBuilder 15: dup 16: invokespecial java/lang/StringBuilder."<init>" 19: aload_1 20: invokevirtual java/lang/StringBuilder.append 23: aload_0 24: getfield OTHER_STR 27: invokevirtual java/lang/StringBuilder.append 30: invokevirtual java/lang/StringBuilder.toString 33: astore_1 34: iinc 2, 1 37: goto 5
  • 144.
    String concatenation String str= ""; for(int i = 0; i < N; i++) { str += OTHER_STR; } 0: ldc String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: sipush N 9: if_icmpge 40 12: new class java/lang/StringBuilder 15: dup 16: invokespecial java/lang/StringBuilder."<init>" 19: aload_1 20: invokevirtual java/lang/StringBuilder.append 23: aload_0 24: getfield OTHER_STR 27: invokevirtual java/lang/StringBuilder.append 30: invokevirtual java/lang/StringBuilder.toString 33: astore_1 34: iinc 2, 1 37: goto 5
  • 145.
    String concatenation String str= ""; for(int i = 0; i < N; i++) { str += OTHER_STR; } 0: ldc String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: sipush N 9: if_icmpge 40 12: new class java/lang/StringBuilder 15: dup 16: invokespecial java/lang/StringBuilder."<init>" 19: aload_1 20: invokevirtual java/lang/StringBuilder.append 23: aload_0 24: getfield OTHER_STR 27: invokevirtual java/lang/StringBuilder.append 30: invokevirtual java/lang/StringBuilder.toString 33: astore_1 34: iinc 2, 1 37: goto 5
  • 146.
    String concatenation String str= ""; for(int i = 0; i < N; i++) { str += OTHER_STR; } 0: ldc String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: sipush N 9: if_icmpge 40 12: new class java/lang/StringBuilder 15: dup 16: invokespecial java/lang/StringBuilder."<init>" 19: aload_1 20: invokevirtual java/lang/StringBuilder.append 23: aload_0 24: getfield OTHER_STR 27: invokevirtual java/lang/StringBuilder.append 30: invokevirtual java/lang/StringBuilder.toString 33: astore_1 34: iinc 2, 1 37: goto 5
  • 147.
    String concatenation String str= ""; for(int i = 0; i < N; i++) { str += OTHER_STR; } 0: ldc String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: sipush N 9: if_icmpge 40 12: new class java/lang/StringBuilder 15: dup 16: invokespecial java/lang/StringBuilder."<init>" 19: aload_1 20: invokevirtual java/lang/StringBuilder.append 23: aload_0 24: getfield OTHER_STR 27: invokevirtual java/lang/StringBuilder.append 30: invokevirtual java/lang/StringBuilder.toString 33: astore_1 34: iinc 2, 1 37: goto 5
  • 148.
    String concatenation String str= ""; for(int i = 0; i < N; i++) { str += OTHER_STR; } 0: ldc String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: sipush N 9: if_icmpge 40 12: new class java/lang/StringBuilder 15: dup 16: invokespecial java/lang/StringBuilder."<init>" 19: aload_1 20: invokevirtual java/lang/StringBuilder.append 23: aload_0 24: getfield OTHER_STR 27: invokevirtual java/lang/StringBuilder.append 30: invokevirtual java/lang/StringBuilder.toString 33: astore_1 34: iinc 2, 1 37: goto 5
  • 149.
    String str =""; for(int i = 0; i < N; i++) { StringBuilder sb = new StringBuilder(); sb.append(str); sb.append(OTHER_STR); str = sb.toString(); } String concatenation
  • 150.
    Object creation: String str= ""; for(int i = 0; i < N; i++) { StringBuilder sb = new StringBuilder(); sb.append(str); sb.append(OTHER_STR); str = sb.toString(); } String concatenation
  • 151.
  • 152.
    String.concat() • Concat costis O(N) + O(M) • Concat returns a new String Object. String str = ""; for(int i = 0; i < N; i++) { str = str.concat(OTHER_STR); }
  • 153.
    String.concat() Object creation: String str= ""; for(int i = 0; i < N; i++) { str = str.concat(OTHER_STR); }
  • 154.
    StringBuilder • StringBuilder.append costis O(M) [M being the length of appended String] StringBuilder sb = new StringBuilder() for(int i = 0; i < N; i++) { sb.append(OTHER_STR); } str = sb.toString();
  • 155.
    StringBuilder sb = newStringBuilder() for(int i = 0; i < N; i++) { sb.append(OTHER_STR); } str = sb.toString(); 0: ldc String 2: astore_1 3: new java/lang/StringBuilder 6: dup 7: invokespecial java/lang/StringBuilder."<init>" 10: astore_2 11: iconst_0 12: istore_3 13: iload_3 14: sipush N 17: if_icmpge 35 20: aload_2 21: aload_0 22: getfield OTHER_STR 25: invokevirtual java/lang/StringBuilder.append 28: pop 29: iinc 3, 1 32: goto 13
  • 156.
    0: ldc String 2:astore_1 3: new java/lang/StringBuilder 6: dup 7: invokespecial java/lang/StringBuilder."<init>" 10: astore_2 11: iconst_0 12: istore_3 13: iload_3 14: sipush N 17: if_icmpge 35 20: aload_2 21: aload_0 22: getfield OTHER_STR 25: invokevirtual java/lang/StringBuilder.append 28: pop 29: iinc 3, 1 32: goto 13 sb = new StringBuilder() for(int i = 0; i < N; i++) { sb.append(OTHER_STR); } str = sb.toString(); StringBuilder
  • 157.
    Object creation: StringBuilder sb= new StringBuilder(); for(int i = 0; i < N; i++) { sb.append(OTHER_STR); } str = sb.toString(); StringBuilder
  • 158.
    String concatenation Use StringBuilder(properly) as much as possible. StringBuffer is the thread safe implementation.
  • 159.
    Strings in casestatements
  • 160.
    public void taskStateMachine(Stringstatus) { switch(status) { case "PENDING": System.out.println("Status pending"); break; case "EXECUTING": System.out.println("Status executing"); break; } }
  • 163.
    Code optimization example: yuv2rgbconverter. Always measure!
  • 164.
  • 166.
    Slightly optimized version precalctables, fixed point operations, 2 pixels per loop…
  • 169.
    Lets compare: Normal, minified,minified with optimizations & jack Minified = obfuscated using Proguard
  • 170.
    Normal Minified Minified& optimized Jack 0 2000 4000 6000 8000 10000 12000 14000 16000 18000 20000 non-optimized optimized
  • 171.
  • 172.
    Tooling Java • javap -c<classfile> Android: •Dexdump -d <dexfile>
  • 173.
  • 174.
    Tooling – Disassembler- ART adb pull /data/dalvik- cache/arm/data@app@<package>- 1@base apk@classes.dex adb shell oatdump --oat-file=/data/dalvik- cache/arm/data@app@<package>- 1@base.apk@classes.dex
  • 175.
    Tooling – PrintAssembly- JIT -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:CompileCommand=print,com.raimon.test.Test::method Under the Hood of the JVM: From Bytecode Through the JIT to Assembly by @alblue http://alblue.bandlem.com/2016/09/javaone-hotspot.html
  • 176.
    Additional References Sinking yourteeth into bytecode by @jakewharton http://jakewharton.com/sinking-your-teeth-into-bytecode/ Exploring Kotlin’s hidden costs by @BladeCoder https://medium.com/@BladeCoder/exploring-kotlins- hidden-costs-part-1-fbb9935d9b62
  • 177.
    Performance measurements Avoid doingmultiple tests in one run JIT might be evil!
  • 178.