SlideShare a Scribd company logo
1 of 126
Download to read offline
Down the Rabbit Hole
An adventure in JVM wonderland
Monday, September 30, 13
Me
• Charles Oliver Nutter
• Red Hat (yes, I have one; no, I don’t wear it)
• JRuby and JVM languages
• JVM hacking and spelunking
• @headius
Monday, September 30, 13
What are we going to
do today?
• Look at some interesting Java features
• See how they’re compiled to bytecode
• Watch what the JVM does with them
• Examine the actual native code they become
Monday, September 30, 13
WHY?!
Monday, September 30, 13
Who AreYou?
• Java developers?
• Performance engineers?
• Debuggers?
• All of the above?
Monday, September 30, 13
Details Matter
• Cool features with hidden costs
• Inner classes
• Structural types in Scala
• Serialization
• How code design impacts performance
• What JVM can and can’t do for you
Monday, September 30, 13
Sufficiently Smart
Compiler
“HighLevelLanguage H may be slower than the
LowLevelLanguage L, but given a
SufficientlySmartCompiler this would not be the case”
http://c2.com/cgi/wiki?SufficientlySmartCompiler
Monday, September 30, 13
Sufficiently Smart
Compiler
If you wait long enough*, the JVM will eventually
optimize everything perfectly and even terrible
code will perform well.
* for some definition of “long”
Monday, September 30, 13
Part One:The Primer
Monday, September 30, 13
Vocabulary
• Source
• The .java text that represents a program
• Bytecode
• The binary version of the program that
all JVMs can load and execute
Monday, September 30, 13
Vocabulary
• Native code
• Machine code specific to the current
platform (OS, CPU) that represents the
program in a form the CPU can execute
directly
• Heap
• The JVM-controlled area of memory
where Java objects live
Monday, September 30, 13
Vocabulary
• JIT
• “Just In Time” (compilation) that turns one
program form into a lower program form,
e.g. bytecode into native code at
runtime
• AOT
• Compilation that occurs before
runtime
Monday, September 30, 13
JVM 101
Java source JVM bytecode
javac
JVM bytecode
Bytecode
interpreter
runs inside gather
information
JIT
compiler
triggers
Native code
produces
executes
backs off
Monday, September 30, 13
Vocabulary
• Inlining
• Inserting the code of a called method
into the caller, avoiding overhead of the
call and optimizing the two together
• Optimization
• Doing the least amount of work needed
to accomplish some goal
Monday, September 30, 13
Inlining Instance
Method
Load target and
arguments
Target type is same?
Method
lookup
Run target
code directly
Yes
No
Run target
method as a call
Monday, September 30, 13
Inlining Static or Special
Method
Load arguments
Run target
code directly
Monday, September 30, 13
Our Tools
• javac, obviously
• javap to dump .class data
• -XX:+PrintCompilation
• -XX:+PrintInlining
• -XX:+PrintAssembly
Monday, September 30, 13
Hello, world!
• We’ll start with something simple.
Monday, September 30, 13
package com.headius.talks.rabbithole;
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}
Monday, September 30, 13
Level 1: Bytecode
• javap
• Java class file disassembler
• Dump structure, data, metadata, and code
Monday, September 30, 13
$ javap -cp dist/RabbitHole.jar 
com.headius.talks.rabbithole.HelloWorld
Compiled from "HelloWorld.java"
public class com.headius.talks.rabbithole.HelloWorld {
public com.headius.talks.rabbithole.HelloWorld();
public static void main(java.lang.String[]);
}
Monday, September 30, 13
$ javap -cp dist/RabbitHole.jar 
-c 
com.headius.talks.rabbithole.HelloWorld
Compiled from "HelloWorld.java"
public class com.headius.talks.rabbithole.HelloWorld {
...
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
8: return
}
Monday, September 30, 13
Our First Bytecodes
• getstatic/putstatic - static field access
• ldc - load constant value on stack
• invokevirtual - call a concrete instance
method
• return - return from a void method
Monday, September 30, 13
$ javap -cp dist/RabbitHole.jar 
-c 
com.headius.talks.rabbithole.HelloWorld
Compiled from "HelloWorld.java"
public class com.headius.talks.rabbithole.HelloWorld {
...
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
8: return
}
Monday, September 30, 13
Level 2: Compiler Logs
• -XX:+PrintCompilation
• Display methods as they compile
• -XX:+PrintInlining
• Display inlined methods as nested
Monday, September 30, 13
JVM JIT
• Code is interpreted first
• After some threshold, JIT fires
• Classic JVM went straight to “client” or
“server”
• Tiered compiler goes to “client plus
profiling” and later “server”
Monday, September 30, 13
public class HelloWorld {
    public static void main(String[] args) {
        for (int i = 0; i < 100000; i++) {
            hello();
        }
    }
    
    private static void hello() {
        System.err.println("Hello, world!");
    }
}
Monday, September 30, 13
$ java -Xbatch
-XX:-TieredCompilation 
-XX:+PrintCompilation 
-cp dist/RabbitHole.jar 
com.headius.talks.rabbithole.HelloWorld 
2> /dev/null
Monday, September 30, 13
83 1 java.lang.String::hashCode (55 bytes)
91 2 java.lang.String::indexOf (70 bytes)
121 3 sun.nio.cs.UTF_8$Encoder::encodeArrayLoop (489 bytes)
137 4 java.nio.Buffer::position (5 bytes)
...
283 47 java.lang.String::indexOf (7 bytes)
285 48 com.headius.talks.rabbithole.HelloWorld::hello (9 bytes)
285 49 ! java.io.PrintStream::println (24 bytes)
295 50 java.io.PrintStream::print (13 bytes)
296 51 ! java.io.PrintStream::write (83 bytes)
301 52 ! java.io.PrintStream::newLine (73 bytes)
302 53 java.io.BufferedWriter::newLine (9 bytes)
302 54 % com.headius.talks.rabbithole.HelloWorld::main @ 2 (18 bytes)
Monday, September 30, 13
83 1 java.lang.String::hashCode (55 bytes)
91 2 java.lang.String::indexOf (70 bytes)
121 3 sun.nio.cs.UTF_8$Encoder::encodeArrayLoop (489 bytes)
137 4 java.nio.Buffer::position (5 bytes)
...
283 47 java.lang.String::indexOf (7 bytes)
285 48 com.headius.talks.rabbithole.HelloWorld::hello (9 bytes)
285 49 ! java.io.PrintStream::println (24 bytes)
295 50 java.io.PrintStream::print (13 bytes)
296 51 ! java.io.PrintStream::write (83 bytes)
301 52 ! java.io.PrintStream::newLine (73 bytes)
302 53 java.io.BufferedWriter::newLine (9 bytes)
302 54 % com.headius.talks.rabbithole.HelloWorld::main @ 2 (18 bytes)
Monday, September 30, 13
$ java -Xbatch 
-XX:-TieredCompilation 
-XX:+PrintCompilation 
-XX:+UnlockDiagnosticVMOptions 
-XX:+PrintInlining 
-cp dist/RabbitHole.jar 
com.headius.talks.rabbithole.HelloWorld
2> /dev/null
Monday, September 30, 13
82 1 b java.lang.String::hashCode (55 bytes)
94 2 b java.lang.String::indexOf (70 bytes)
@ 66 java.lang.String::indexOfSupplementary (71 bytes) too big
132 3 b sun.nio.cs.UTF_8$Encoder::encodeArrayLoop (489 bytes)
@ 1 java.nio.CharBuffer::array (35 bytes) inline (hot)
@ 6 java.nio.CharBuffer::arrayOffset (35 bytes) inline (hot)
...
397 48 b com.headius.talks.rabbithole.HelloWorld::hello (9 bytes)
!m @ 5 java.io.PrintStream::println (24 bytes) inline (hot)
@ 6 java.io.PrintStream::print (13 bytes) inline (hot)
...
446 54 % b com.headius.talks.rabbithole.HelloWorld::main @ 2 (18 bytes)
@ 8 com.headius.talks.rabbithole.HelloWorld::hello (9 bytes)
already compiled into a big method
Monday, September 30, 13
82 1 b java.lang.String::hashCode (55 bytes)
94 2 b java.lang.String::indexOf (70 bytes)
@ 66 java.lang.String::indexOfSupplementary (71 bytes) too big
132 3 b sun.nio.cs.UTF_8$Encoder::encodeArrayLoop (489 bytes)
@ 1 java.nio.CharBuffer::array (35 bytes) inline (hot)
@ 6 java.nio.CharBuffer::arrayOffset (35 bytes) inline (hot)
...
397 48 b com.headius.talks.rabbithole.HelloWorld::hello (9 bytes)
!m @ 5 java.io.PrintStream::println (24 bytes) inline (hot)
@ 6 java.io.PrintStream::print (13 bytes) inline (hot)
...
446 54 % b com.headius.talks.rabbithole.HelloWorld::main @ 2 (18 bytes)
@ 8 com.headius.talks.rabbithole.HelloWorld::hello (9 bytes)
already compiled into a big method
Monday, September 30, 13
Level 3: Native Code
• -XX:+PrintAssembly
• Dumps “human readable” JITed code
• Google for “hotspot printassembly”
• Aren’t you excited?!
Monday, September 30, 13
$ java -Xbatch 
-XX:-TieredCompilation 
-XX:+UnlockDiagnosticVMOptions 
-XX:+PrintAssembly 
-cp dist/RabbitHole.jar 
com.headius.talks.rabbithole.HelloWorld
2> /dev/null
| less
Monday, September 30, 13
Decoding compiled method 0x0000000110526110:
Code:
[Entry Point]
[Verified Entry Point]
[Constants]
# {method}
{0x00000001100a6420} 'hello' '()V' in 'com/headius/talks/rabbithole/HelloWorld'
# [sp+0x70] (sp of caller)
0x0000000110526300: mov %eax,-0x14000(%rsp)
0x0000000110526307: push %rbp
0x0000000110526308: sub $0x60,%rsp ;*synchronization entry
; - com.headius.talks.rabbithole.HelloWorld::hello@-1 (line 13)
0x000000011052630c: movabs $0x7aaa80c78,%r10 ; {oop(a 'java/lang/Class' = 'java/lang/System')}
0x0000000110526316: mov 0x70(%r10),%r11d ;*getstatic err
; - com.headius.talks.rabbithole.HelloWorld::hello@0 (line 13)
0x000000011052631a: mov %r11d,0x10(%rsp)
0x000000011052631f: test %r11d,%r11d
0x0000000110526322: je 0x000000011052664e ;*invokevirtual println
; - com.headius.talks.rabbithole.HelloWorld::hello@5 (line 13)
Monday, September 30, 13
Too big!
• Server produces ~2700 bytes of ASM
• Client produces ~594 bytes of ASM
• Most of server output is from inlining
• More profiling, more code, more perf
• ...and slower startup
Monday, September 30, 13
public class Tiny1 {
    public static void main(String[] args) {
        for (int i = 0; i < 100000; i++) {
            tiny();
        }
    }
    
    public static int tiny() {
        return 1 + 1;
    }
}
Monday, September 30, 13
public static int tiny();
Code:
0: iconst_2
1: ireturn
iconst_2: load integer 2 on stack
ireturn: return int
Monday, September 30, 13
110 3 b com.headius.talks.rabbithole.Tiny1::tiny (2 bytes)
111 4 % b com.headius.talks.rabbithole.Tiny1::main @ 2 (19 bytes)
@ 8 com.headius.talks.rabbithole.Tiny1::tiny
(2 bytes) inline (hot)
Monday, September 30, 13
{0x000000010994c3c0} 'tiny' '()I' in 'com/headius/talks/rabbithole/Tiny1'
# [sp+0x40] (sp of caller)
0x0000000109e566a0: mov %eax,-0x14000(%rsp)
0x0000000109e566a7: push %rbp
0x0000000109e566a8: sub $0x30,%rsp ;*iconst_2
; -
com.headius.talks.rabbithole.Tiny1::tiny@0 (line 11)
0x0000000109e566ac: mov $0x2,%eax
0x0000000109e566b1: add $0x30,%rsp
0x0000000109e566b5: pop %rbp
0x0000000109e566b6: test %eax,-0x9a05bc(%rip) # 0x00000001094b6100
; {poll_return}
0x0000000109e566bc: retq
Monday, September 30, 13
{0x000000010994c3c0} 'tiny' '()I' in 'com/headius/talks/rabbithole/Tiny1'
# [sp+0x40] (sp of caller)
0x0000000109e566a0: mov %eax,-0x14000(%rsp)
0x0000000109e566a7: push %rbp
0x0000000109e566a8: sub $0x30,%rsp ;*iconst_2
; -
com.headius.talks.rabbithole.Tiny1::tiny@0 (line 11)
0x0000000109e566ac: mov $0x2,%eax
0x0000000109e566b1: add $0x30,%rsp
0x0000000109e566b5: pop %rbp
0x0000000109e566b6: test %eax,-0x9a05bc(%rip) # 0x00000001094b6100
; {poll_return}
0x0000000109e566bc: retq
Monday, September 30, 13
{0x000000010e67d300} 'main' '([Ljava/lang/String;)V' in 'com/headius/talks/rabbithole/Tiny1'
0x000000010eb879a0: mov %eax,-0x14000(%rsp)
0x000000010eb879a7: push %rbp
0x000000010eb879a8: sub $0x40,%rsp ;*iconst_0
; - com.headius.talks.rabbithole.Tiny1::main@0 (line 5)
0x000000010eb879ac: mov $0x0,%esi
0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1
; - com.headius.talks.rabbithole.Tiny1::main@2 (line 5)
0x000000010eb879b6: xchg %ax,%ax
0x000000010eb879b8: inc %esi ; OopMap{off=26}
;*goto
; - com.headius.talks.rabbithole.Tiny1::main@15 (line 5)
0x000000010eb879ba: test %eax,-0x9a08c0(%rip) # 0x000000010e1e7100
;*goto
; - com.headius.talks.rabbithole.Tiny1::main@15 (line 5)
; {poll}
0x000000010eb879c0: cmp $0x186a0,%esi
0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge
; - com.headius.talks.rabbithole.Tiny1::main@5 (line 5)
0x000000010eb879c8: add $0x40,%rsp
0x000000010eb879cc: pop %rbp
0x000000010eb879cd: test %eax,-0x9a08d3(%rip) # 0x000000010e1e7100
; {poll_return}
0x000000010eb879d3: retq ;*return
; - com.headius.talks.rabbithole.Tiny1::main@18 (line 8)
Monday, September 30, 13
0x000000010eb879a0: mov %eax,-0x14000(%rsp)
0x000000010eb879a7: push %rbp
0x000000010eb879a8: sub $0x40,%rsp ;*iconst_0
0x000000010eb879ac: mov $0x0,%esi
0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1
0x000000010eb879b6: xchg %ax,%ax
0x000000010eb879b8: inc %esi ; OopMap{off=26}
0x000000010eb879ba: test %eax,-0x9a08c0(%rip) # 0x000000010e1e7100
0x000000010eb879c0: cmp $0x186a0,%esi
0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge
0x000000010eb879c8: add $0x40,%rsp
0x000000010eb879cc: pop %rbp
0x000000010eb879cd: test %eax,-0x9a08d3(%rip) # 0x000000010e1e7100
0x000000010eb879d3: retq ;*return
Monday, September 30, 13
0x000000010eb879a0: mov %eax,-0x14000(%rsp)
0x000000010eb879a7: push %rbp
0x000000010eb879a8: sub $0x40,%rsp ;*iconst_0
0x000000010eb879ac: mov $0x0,%esi
0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1
0x000000010eb879b6: xchg %ax,%ax
0x000000010eb879b8: inc %esi ; OopMap{off=26}
0x000000010eb879ba: test %eax,-0x9a08c0(%rip) # 0x000000010e1e7100
0x000000010eb879c0: cmp $0x186a0,%esi
0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge
0x000000010eb879c8: add $0x40,%rsp
0x000000010eb879cc: pop %rbp
0x000000010eb879cd: test %eax,-0x9a08d3(%rip) # 0x000000010e1e7100
0x000000010eb879d3: retq ;*return
Monday, September 30, 13
0x000000010eb879ac: mov $0x0,%esi
0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1
0x000000010eb879b6: xchg %ax,%ax
0x000000010eb879b8: inc %esi ; OopMap{off=26}
0x000000010eb879ba: test %eax,-0x9a08c0(%rip) # 0x000000010e1e7100
0x000000010eb879c0: cmp $0x186a0,%esi
0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge
0x000000010eb879cd: test %eax,-0x9a08d3(%rip) # 0x000000010e1e7100
0x000000010eb879d3: retq ;*return
Monday, September 30, 13
0x000000010eb879ac: mov $0x0,%esi
0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1
0x000000010eb879b6: xchg %ax,%ax
0x000000010eb879b8: inc %esi ; OopMap{off=26}
0x000000010eb879ba: test %eax,-0x9a08c0(%rip) # 0x000000010e1e7100
0x000000010eb879c0: cmp $0x186a0,%esi
0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge
0x000000010eb879cd: test %eax,-0x9a08d3(%rip) # 0x000000010e1e7100
0x000000010eb879d3: retq ;*return
Monday, September 30, 13
0x000000010eb879ac: mov $0x0,%esi
0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1
0x000000010eb879b6: xchg %ax,%ax
0x000000010eb879b8: inc %esi ; OopMap{off=26}
0x000000010eb879c0: cmp $0x186a0,%esi
0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge
0x000000010eb879d3: retq ;*return
Monday, September 30, 13
0x000000010eb879ac: mov $0x0,%esi
0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1
0x000000010eb879b6: xchg %ax,%ax
0x000000010eb879b8: inc %esi ; OopMap{off=26}
0x000000010eb879c0: cmp $0x186a0,%esi
0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge
0x000000010eb879d3: retq ;*return
Monday, September 30, 13
0x000000010eb879ac: mov $0x0,%esi
0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1
0x000000010eb879b8: inc %esi ; OopMap{off=26}
0x000000010eb879c0: cmp $0x186a0,%esi
0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge
0x000000010eb879d3: retq ;*return
Monday, September 30, 13
1: mov $0,%esi
2: jmpq 4:
3: inc %esi
4: cmp $1000000,%esi
5: jl 3:
6: retq
Monday, September 30, 13
1: retq
Monday, September 30, 13
It’s not that hard
once you know what to
look at.
Monday, September 30, 13
Part 2:The Fun Stuff
Monday, September 30, 13
Java Features
• final fields
• synchronized
• string switch
• lambda
Monday, September 30, 13
#1: Final Fields
• Final fields can’t be modified
• The pipeline can take advantage
• ...but it doesn’t always
Monday, September 30, 13
public class Fields {
    private static final String MY_STRING =
"This is a static string";
    private static final String MY_PROPERTY =
System.getProperty("java.home");
    
    public static void main(String[] args) {
        System.out.println(MY_STRING);
        System.out.println(MY_PROPERTY);
}
}
Monday, September 30, 13
public static void main(java.lang.String[]);
Code:
0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #9 // String This is a static string
5: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
11: getstatic #11 // Field MY_PROPERTY:Ljava/lang/String;
14: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    private static final String MY_STRING =
"This is a static string";
    private static final String MY_PROPERTY =
System.getProperty("java.home");
Monday, September 30, 13
    private static int addHashes() {
        return MY_STRING.hashCode() + MY_PROPERTY.hashCode();
    }
Monday, September 30, 13
movabs $0x7aab6c4f8,%r10 ; {oop("This is a static string")}
mov %eax,0x10(%r10) ;*iload_1
; - String::hashCode@53 (line 1467)
; - Fields::addHashes@2 (line 36)
movabs $0x7aaa97a98,%rcx
; {oop(".../jdk1.8.0.jdk/Contents/Home/jre")}
mov 0x10(%rcx),%r10d ;*getfield hash
; - String::hashCode@1 (line 1458)
; - Fields::addHashes@8 (line 36)
Monday, September 30, 13
    private final String myString = "This is an instance string";
    private final String myProperty = System.getProperty("java.home");
    public int addHashes2() {
        return myString.hashCode() + myProperty.hashCode();
    }    
Monday, September 30, 13
private int addHashes2();
Code:
0: ldc #2 // String This is an instance string
2: invokevirtual #18 // Method java/lang/String.hashCode:()I
5: aload_0
6: getfield #6 // Field myProperty:Ljava/lang/String;
9: invokevirtual #18 // Method java/lang/String.hashCode:()I
12: iadd
13: ireturn
Monday, September 30, 13
movabs $0x7aab6d318,%rcx ; {oop("This is an instance string")}
mov 0x10(%rcx),%r10d ;*getfield hash
; - String::hashCode@1 (line 1458)
; - Fields::addHashes2@2 (line 40)
Monday, September 30, 13
mov 0x10(%rsi),%ecx ;*getfield myProperty
; - Fields::addHashes2@6 (line 40)
mov 0x10(%r12,%rcx,8),%eax ;*getfield hash
; - String::hashCode@1 (line 1458)
; - Fields::addHashes2@9 (line 40)
Monday, September 30, 13
ACHIEVEMENT UNLOCKED:
Find something Hotspot could do better
Monday, September 30, 13
#2: Concurrency Stuff
• What does “synchronized” do?
• What does “volatile” do?
Monday, September 30, 13
public class Concurrency {
    public static void main(String[] args) {
        System.out.println(getTime());
        System.out.println(getTimeSynchronized());
    }
    
    public static long getTime() {
        return System.currentTimeMillis();
    }
    
    public static synchronized long getTimeSynchronized() {
        return System.currentTimeMillis();
    }
}
Monday, September 30, 13
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: invokestatic #3 // Method getTime:()J
6: invokevirtual #4 // Method java/io/PrintStream.println:(J)V
9: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
12: invokestatic #5 // Method getTimeSynchronized:()J
15: invokevirtual #4 // Method java/io/PrintStream.println:(J)V
Monday, September 30, 13
public static long getTime();
Code:
0: invokestatic #7 // Method java/lang/System.currentTimeMillis:()J
3: lreturn
public static synchronized long getTimeSynchronized();
Code:
0: invokestatic #7 // Method java/lang/System.currentTimeMillis:()J
3: lreturn
Monday, September 30, 13
'getTime' '()J' in 'com/headius/talks/rabbithole/Concurrency'
movabs $0x1015dbd3e,%r10
callq *%r10 ;*invokestatic currentTimeMillis
; - Concurrency::getTime@0 (line 22)
retq
Monday, September 30, 13
'getTime' '()J' in 'com/headius/talks/rabbithole/Concurrency'
movabs $0x1015dbd3e,%r10
callq *%r10 ;*invokestatic currentTimeMillis
; - Concurrency::getTime@0 (line 22)
retq
Monday, September 30, 13
????
Monday, September 30, 13
movabs $0x7aab6bee8,%r10 ; {oop(a 'java/lang/Class' = '.../Concurrency')}
mov (%r10),%rax
mov %rax,%r10
and $0x7,%r10
cmp $0x5,%r10
jne 0x000000010ef0665f
mov $0xdf3803fe,%r11d ; {metadata('java/lang/Class')}
mov 0xa8(%r12,%r11,8),%r10
mov %r10,%r11
or %r15,%r11
mov %r11,%r8
xor %rax,%r8
$0xffffffffffffff87,%r8
jne 0x000000010ef068e4
mov %r14d,(%rsp) ;*synchronization entry
; - Concurrency::getTimeSynchronized@-1 (line 26)
; - Concurrency::main@58 (line 16)
movabs $0x10de5ad3e,%r10
callq *%r10 ;*invokestatic currentTimeMillis
; - Concurrency::getTimeSynchronized@0 (line 26)
; - Concurrency::main@58 (line 16)
Monday, September 30, 13
movabs $0x7aab6bee8,%r10 ; {oop(a 'java/lang/Class' = '.../Concurrency')}
mov (%r10),%rax
mov %rax,%r10
and $0x7,%r10
cmp $0x5,%r10
jne 0x000000010ef0665f
mov $0xdf3803fe,%r11d ; {metadata('java/lang/Class')}
mov 0xa8(%r12,%r11,8),%r10
mov %r10,%r11
or %r15,%r11
mov %r11,%r8
xor %rax,%r8
$0xffffffffffffff87,%r8
jne 0x000000010ef068e4
mov %r14d,(%rsp) ;*synchronization entry
; - Concurrency::getTimeSynchronized@-1 (line 26)
; - Concurrency::main@58 (line 16)
movabs $0x10de5ad3e,%r10
callq *%r10 ;*invokestatic currentTimeMillis
; - Concurrency::getTimeSynchronized@0 (line 26)
; - Concurrency::main@58 (line 16)
Monday, September 30, 13
Vocabulary
• Lock coarsening
• Expanding the use of multiple fine-
grained locks into a single coarse-grained
lock
• Lock eliding
• Eliminating locking when it will not affect
the behavior of the program
Monday, September 30, 13
movabs $0x7aab6bee8,%r10 ; {oop(a 'java/lang/Class' = '.../Concurrency')}
mov (%r10),%rax
mov %rax,%r10
and $0x7,%r10
cmp $0x5,%r10
jne 0x000000010ef0665f
mov $0xdf3803fe,%r11d ; {metadata('java/lang/Class')}
mov 0xa8(%r12,%r11,8),%r10
mov %r10,%r11
or %r15,%r11
mov %r11,%r8
xor %rax,%r8
$0xffffffffffffff87,%r8
jne 0x000000010ef068e4
mov %r14d,(%rsp) ;*synchronization entry
; - Concurrency::getTimeSynchronized@-1 (line 26)
; - Concurrency::main@58 (line 16)
movabs $0x10de5ad3e,%r10
callq *%r10 ;*invokestatic currentTimeMillis
; - Concurrency::getTimeSynchronized@0 (line 26)
; - Concurrency::main@58 (line 16)
Monday, September 30, 13
0x000000010ef0665f: movabs $0x7aab6bee8,%r11
; {oop(a 'java/lang/Class' = '.../Concurrency')}
0x000000010ef06669: lea 0x10(%rsp),%rbx
0x000000010ef0666e: mov (%r11),%rax
0x000000010ef06671: test $0x2,%eax
0x000000010ef06676: jne 0x000000010ef0669f
0x000000010ef0667c: or $0x1,%eax
0x000000010ef0667f: mov %rax,(%rbx)
0x000000010ef06682: lock cmpxchg %rbx,(%r11)
0x000000010ef06687: je 0x000000010ef066bc
Monday, September 30, 13
Volatile
• Forces commit of memory
• Forces code ordering
• Prevents some optimizations
• Similar impact to unecessary locking
• ...but it can’t ever be removed
Monday, September 30, 13
11345d823: mov 0x70(%r8),%r9d ;*getstatic NULL_OBJECT_ARRAY
; - org.jruby.RubyBasicObject::<init>@5 (line 76)
; - org.jruby.RubyObject::<init>@2 (line 118)
; - org.jruby.RubyNumeric::<init>@2 (line 111)
; - org.jruby.RubyInteger::<init>@2 (line 95)
; - org.jruby.RubyFixnum::<init>@5 (line 112)
; - org.jruby.RubyFixnum::newFixnum@25 (line 173)
11345d827: mov %r9d,0x14(%rax)
11345d82b: lock addl $0x0,(%rsp) ;*putfield varTable
; - org.jruby.RubyBasicObject::<init>@8 (line 76)
; - org.jruby.RubyObject::<init>@2 (line 118)
; - org.jruby.RubyNumeric::<init>@2 (line 111)
; - org.jruby.RubyInteger::<init>@2 (line 95)
; - org.jruby.RubyFixnum::<init>@5 (line 112)
; - org.jruby.RubyFixnum::newFixnum@25 (line 173)
LOCK
Code from a RubyBasicObject’s default constructor.
Why are we doing a volatile write in the constructor?
Wednesday, July 27, 2011
Monday, September 30, 13
public class RubyBasicObject ... {
private static final boolean DEBUG = false;
private static final Object[] NULL_OBJECT_ARRAY = new Object[0];
// The class of this object
protected transient RubyClass metaClass;
// zeroed by jvm
protected int flags;
// variable table, lazily allocated as needed (if needed)
private volatile Object[] varTable = NULL_OBJECT_ARRAY;
LOCK
Maybe it’s not such a good idea to pre-init a volatile?
Wednesday, July 27, 2011
Monday, September 30, 13
#3: String Switch
• Added in Java 7
• ...and there was much rejoicing
• But how does it really work?
Monday, September 30, 13
A Normal Switch
• Variable switch parameter
• Constant case values
• Branch based on a table (fast) for narrow
range of cases
• Branch based on a lookup (less fast) for
broad range of cases
Monday, September 30, 13
public class StringSwitch {
    public static void main(String[] args) {
        String count = "unknown";
        switch (args.length) {
            case 0: count = "zero"; break;
            case 1: count = "one"; break;
            case 2: count = "two"; break;
        }
...
Monday, September 30, 13
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String unknown
2: astore_1
3: aload_0
4: arraylength
5: tableswitch { // 0 to 2
0: 32
1: 38
2: 44
default: 47
}
32: ldc #3 // String zero
34: astore_1
35: goto 47
38: ldc #4 // String one
40: astore_1
41: goto 47
44: ldc #5 // String two
46: astore_1
Monday, September 30, 13
switch (args.length) {
    case 2000000: count = "two million"; break;
    case 1000000: count = "one million"; break;
    case 3000000: count = "three million"; break;
}
Monday, September 30, 13
49: lookupswitch { // 3
1000000: 90
2000000: 84
3000000: 96
default: 99
}
Monday, September 30, 13
Comparison
• tableswitch is O(1)
• Indexed lookup of target
• lookupswitch is O(log n)
• Binary search for target
Monday, September 30, 13
Get to the point already!
Monday, September 30, 13
The Point
• What kind of switch do we use for String?
• Table doesn’t work for hashcodes
• Lookup might collide
• Answer: both, plus .equals()
Monday, September 30, 13
    static String chooseGreeting(String language) {
        switch (language) {
            case "Java": return "I love to hate you!";
            case "Scala": return "I love you, I think!";
            case "Clojure": return "(love I you)";
            case "Groovy": return "I love ?: you";
            case "Ruby": return "I.love? you # => true";
            default: return "Who are you?";
        }
    }
Monday, September 30, 13
static java.lang.String chooseGreeting(java.lang.String);
Code:
0: aload_0
1: astore_1
2: iconst_m1
3: istore_2
4: aload_1
5: invokevirtual #16 // Method java/lang/String.hashCode:()I
8: lookupswitch { // 5
-1764029756: 88
2301506: 60
2558458: 116
79698214: 74
2141368366: 102
default: 127
}
Hidden int variable...
Monday, September 30, 13
74: aload_1
75: ldc #14 // String Scala
77: invokevirtual #17 // Method String.equals:(Ljava/lang/Object;)Z
80: ifeq 127
83: iconst_1
84: istore_2
Same hidden int variable now = 1
Monday, September 30, 13
127: iload_2
128: tableswitch { // 0 to 4
0: 164
1: 167
2: 170
3: 173
4: 176
default: 179
}
164: ldc #20 // String I love to hate you!
166: areturn
167: ldc #21 // String I love you, I think!
169: areturn
170: ldc #22 // String (love I you)
172: areturn
173: ldc #23 // String I love ?: you
175: areturn
176: ldc #24 // String I.love? you # => true
178: areturn
179: ldc #25 // String Who are you?
181: areturn
A-ha! There it is!
Monday, September 30, 13
   static String chooseGreeting2(String language) {
       int hash = language.hashCode();
       int target = -1;
       switch (hash) {
           case 2301506: if (language.equals("Java")) target = 0; break;
           case 79698214: if (language.equals("Scala"))target = 1; break;
           case -1764029756: if (language.equals("Clojure"))target = 2; break;
           case 2141368366: if (language.equals("Groovy"))target = 3; break;
           case 2558458: if (language.equals("Ruby"))target = 3; break;
       }
       switch (target) {
           case 0: return "I love to hate you!";
           case 1: return "I love you, I think!";
           case 2: return "(love I you)";
           case 3: return "I love ?: you";
           case 4: return "I.love? you # => true";
           default: return "Who are you?";
       }
   }
Monday, September 30, 13
It’s just a hash table!
Monday, September 30, 13
#4: Lambda Expressions
• New for Java 8
• ...and there was much rejoicing
• Key goals
• Lighter-weight than inner classes
• No class-per-lambda
• Optimizable by JVM
Monday, September 30, 13
public class LambdaStuff {
    public static void main(String[] args) {
        List<String> list = Arrays.asList(
                "Clojure",
                "Java",
                "Ruby",
                "Groovy",
                "Scala"
        );
        
        for (int i = 0; i < 100000; i++) {
            doSort(list);
            getRest(list);
            getAllCaps(list);
            getInitials(list);
            getInitialsManually(list);
        }
Monday, September 30, 13
   public static void doSort(List<String> input) {
       Collections.sort(input,
(a,b)->Integer.compare(a.length(), b.length()));
   }
Monday, September 30, 13
public static void doSort(java.util.List<java.lang.String>);
Code:
0: aload_0
1: invokedynamic #36, 0
// InvokeDynamic #4:compare:()Ljava/util/Comparator;
6: invokestatic #37
// Method java/util/Collections.sort ...
9: return
Monday, September 30, 13
public static void doSort(java.util.List<java.lang.String>);
Code:
0: aload_0
1: invokedynamic #36, 0
// InvokeDynamic #4:compare:()Ljava/util/Comparator;
6: invokestatic #37
// Method java/util/Collections.sort ...
9: return
InvokeDynamic is used to create the initial lambda
object and then cache it forever.
Compare to anonymous inner classes, where an
instance is created every time.
Monday, September 30, 13
$ javap -cp dist/RabbitHole.jar 
-verbose 
-c 
com.headius.talks.rabbithole.LambdaStuff
Monday, September 30, 13
BootstrapMethods:
...
4: #142 invokestatic java/lang/invoke/LambdaMetafactory.metafactory...
...bunch of types here
Method arguments:
#167 (Ljava/lang/Object;Ljava/lang/Object;)I
#168 invokestatic LambdaStuff.lambda$2:(Ljava/lang/String;Ljava/lang/String;)I
#169 (Ljava/lang/String;Ljava/lang/String;)I
LambdaMetaFactory generates an implementation of
our interface (Comparator here) using
Method Handles (from JSR292)
Monday, September 30, 13
BootstrapMethods:
...
4: #142 invokestatic java/lang/invoke/LambdaMetafactory.metafactory...
...bunch of types here
Method arguments:
#167 (Ljava/lang/Object;Ljava/lang/Object;)I
#168 invokestatic LambdaStuff.lambda$2:(Ljava/lang/String;Ljava/lang/String;)I
#169 (Ljava/lang/String;Ljava/lang/String;)I
LambdaMetaFactory generates an implementation of
our interface (Comparator here) using
Method Handles (from JSR292)
Monday, September 30, 13
private static int lambda$2(java.lang.String, java.lang.String);
Code:
0: aload_0
1: invokevirtual #53 // Method java/lang/String.length:()I
4: aload_1
5: invokevirtual #53 // Method java/lang/String.length:()I
8: invokestatic #54 // Method java/lang/Integer.compare:(II)I
11: ireturn
Lambda body is just a static method;
all state is passed to it.
Because the wrapper is generated and the body
is just a static method, we have no extra classes
and potentially no allocation.
Monday, September 30, 13
Will It Blend?
Monday, September 30, 13
The Problem
• In order to inline code, we need:
• A consistent target method
• A unique path through the code
• Collections.sort’s lambda callback
• Will see many different methods
• Will be called via many different paths
Monday, September 30, 13
Caller 1
Caller 2
Caller 3
Caller 4
sort
Lambda 1
Lambda 2
Lambda 3
Lambda 4
Too many paths!
JVM can’t cope!
Monday, September 30, 13
    public static String getInitials(List<String> input) {
        return input.stream()
                .map(x->x.substring(0,1))
                .collect(Collectors.joining());
    }
    
    public static String getInitialsManually(List<String> input) {
        StringBuilder builder = new StringBuilder();
        UnaryOperator<String> initial = (String x)->x.substring(0,1);
        for (String s : input) {
            builder.append(initial.apply(s));
        }
        return builder.toString();
    }
Monday, September 30, 13
   public static void time(Object name, int iterations, Runnable body) {
       long start = System.currentTimeMillis();
       for (int i = 0; i < iterations; i++) {
           body.run();
       }
       System.out.println(name.toString()
+ ": "
+ (System.currentTimeMillis() - start));
   }
Monday, September 30, 13
        Function<List<String>, String> getInitials =
LambdaStuff::getInitials;
        Function<List<String>, String> getInitialsManually =
LambdaStuff::getInitialsManually;
        
        for (int i = 0; i < 10; i++) {
            time("getInitials", 1000000,
()->getInitials.apply(list));
            time("getInitialsManually", 1000000,
()->getInitialsManually.apply(list));
        }
Monday, September 30, 13
Drum roll, please...
Monday, September 30, 13
    public static String getInitials(List<String> input) {
        return input.stream()
                .map(x->x.substring(0,1))
                .collect(Collectors.joining());
    }
mov %r10d,0x24(%r9) ;*putfield nextStage
; - java.util.stream.AbstractPipeline::<init>@28 (line 200)
; - java.util.stream.ReferencePipeline::<init>@3 (line 94)
; - java.util.stream.ReferencePipeline$StatelessOp::<init>@3 (line 627)
; - java.util.stream.ReferencePipeline$3::<init>@16 (line 188)
; - java.util.stream.ReferencePipeline::map@22 (line 187)
; - com.headius.talks.rabbithole.LambdaStuff::getInitials@11 (line 57)
Methods like map() and collect() inline...
Monday, September 30, 13
    public static String getInitials(List<String> input) {
        return input.stream()
                .map(x->x.substring(0,1))
                .collect(Collectors.joining());
    }
callq 0x0000000105973f20 ; OopMap{rbp=Oop [0]=NarrowOop off=2776}
;*invokeinterface apply
; - java.util.stream.ReferencePipeline::collect@118 (line 512)
; {runtime_call}
But they can’t inline all those lambdas.
Monday, September 30, 13
mov 0x60(%r15),%rcx
mov %rcx,%r10
add $0x18,%r10
cmp 0x70(%r15),%r10
jae 0x0000000104548d78
mov %r10,0x60(%r15)
prefetchnta 0xc0(%r10)
mov $0xdf3802e6,%r10d ; {metadata('java/lang/String')}
mov 0xa8(%r12,%r10,8),%r10
mov %r10,(%rcx)
movl $0xdf3802e6,0x8(%rcx) ; {metadata('java/lang/String')}
mov %r12d,0xc(%rcx)
mov %r12,0x10(%rcx) ;*new ; - String::substring@65 (line 1961)
; - LambdaStuff::lambda$6@3 (line 75)
; - LambdaStuff$$Lambda$9::apply@4
; - LambdaStuff::getInitialsManually@45 (line 77)
    public static String getInitialsManually(List<String> input) {
        StringBuilder builder = new StringBuilder();
        UnaryOperator<String> initial = (String x)->x.substring(0,1);
        for (String s : input) {
            builder.append(initial.apply(s));
        }
        return builder.toString();
    }
Monday, September 30, 13
mov 0x60(%r15),%rcx
mov %rcx,%r10
add $0x18,%r10
cmp 0x70(%r15),%r10
jae 0x0000000104548d78
mov %r10,0x60(%r15)
prefetchnta 0xc0(%r10)
mov $0xdf3802e6,%r10d ; {metadata('java/lang/String')}
mov 0xa8(%r12,%r10,8),%r10
mov %r10,(%rcx)
movl $0xdf3802e6,0x8(%rcx) ; {metadata('java/lang/String')}
mov %r12d,0xc(%rcx)
mov %r12,0x10(%rcx) ;*new ; - String::substring@65 (line 1961)
; - LambdaStuff::lambda$6@3 (line 75)
; - LambdaStuff$$Lambda$9::apply@4
; - LambdaStuff::getInitialsManually@45 (line 77)
    public static String getInitialsManually(List<String> input) {
        StringBuilder builder = new StringBuilder();
        UnaryOperator<String> initial = (String x)->x.substring(0,1);
        for (String s : input) {
            builder.append(initial.apply(s));
        }
        return builder.toString();
    }
Monday, September 30, 13
Lessons
Monday, September 30, 13
The JVM is not perfect.
Monday, September 30, 13
Every feature has a cost.
Monday, September 30, 13
You’ll be a better
developer if you
remember those facts...
Monday, September 30, 13
...and you aren’t afraid
to go down the
rabbit hole.
Monday, September 30, 13
ThankYou!
• Charles Oliver Nutter
• @headius
• headius@headius.com
• http://blog.headius.com
Monday, September 30, 13
BONUS ROUND
Monday, September 30, 13
#5: Escape Analysis
Monday, September 30, 13
Vocabulary
• Escape analysis
• Determining that the data enclosed
inside an object is the only part of the
object needed, so the object does not
need to be allocated
Monday, September 30, 13
Escape Analysis
Object created
Object goes
out of scope
Object used only
in this method
Field data put into
locals
No object to
dereference
Object data used
from fields
Monday, September 30, 13
Breaking EA
• Object assigned to a non-EA object’s field
• Object may go to a method not inlined
• Object may go to a branch not yet followed
• or potentially, crosses any branch at all
Monday, September 30, 13

More Related Content

What's hot

JVM for Dummies - OSCON 2011
JVM for Dummies - OSCON 2011JVM for Dummies - OSCON 2011
JVM for Dummies - OSCON 2011Charles Nutter
 
Do we need Unsafe in Java?
Do we need Unsafe in Java?Do we need Unsafe in Java?
Do we need Unsafe in Java?Andrei Pangin
 
JavaOne 2011 - JVM Bytecode for Dummies
JavaOne 2011 - JVM Bytecode for DummiesJavaOne 2011 - JVM Bytecode for Dummies
JavaOne 2011 - JVM Bytecode for DummiesCharles Nutter
 
Everything you wanted to know about Stack Traces and Heap Dumps
Everything you wanted to know about Stack Traces and Heap DumpsEverything you wanted to know about Stack Traces and Heap Dumps
Everything you wanted to know about Stack Traces and Heap DumpsAndrei Pangin
 
JRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVMJRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVMCharles Nutter
 
Down to Stack Traces, up from Heap Dumps
Down to Stack Traces, up from Heap DumpsDown to Stack Traces, up from Heap Dumps
Down to Stack Traces, up from Heap DumpsAndrei Pangin
 
The Art of JVM Profiling
The Art of JVM ProfilingThe Art of JVM Profiling
The Art of JVM ProfilingAndrei Pangin
 
JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015Charles Nutter
 
Everything is Permitted: Extending Built-ins
Everything is Permitted: Extending Built-insEverything is Permitted: Extending Built-ins
Everything is Permitted: Extending Built-insAndrew Dupont
 
Unleash your inner console cowboy
Unleash your inner console cowboyUnleash your inner console cowboy
Unleash your inner console cowboyKenneth Geisshirt
 
Why GC is eating all my CPU?
Why GC is eating all my CPU?Why GC is eating all my CPU?
Why GC is eating all my CPU?Roman Elizarov
 
Oscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast LaneOscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast LaneAndres Almiray
 
Python在豆瓣的应用
Python在豆瓣的应用Python在豆瓣的应用
Python在豆瓣的应用Qiangning Hong
 
Building High Performance Android Applications in Java and C++
Building High Performance Android Applications in Java and C++Building High Performance Android Applications in Java and C++
Building High Performance Android Applications in Java and C++Kenneth Geisshirt
 
Building a java tracer
Building a java tracerBuilding a java tracer
Building a java tracerrahulrevo
 
Mastering java bytecode with ASM - GeeCON 2012
Mastering java bytecode with ASM - GeeCON 2012Mastering java bytecode with ASM - GeeCON 2012
Mastering java bytecode with ASM - GeeCON 2012Anton Arhipov
 
Rust tutorial from Boston Meetup 2015-07-22
Rust tutorial from Boston Meetup 2015-07-22Rust tutorial from Boston Meetup 2015-07-22
Rust tutorial from Boston Meetup 2015-07-22nikomatsakis
 
Silicon Valley JUG: JVM Mechanics
Silicon Valley JUG: JVM MechanicsSilicon Valley JUG: JVM Mechanics
Silicon Valley JUG: JVM MechanicsAzul Systems, Inc.
 
Inside the JVM - Follow the white rabbit!
Inside the JVM - Follow the white rabbit!Inside the JVM - Follow the white rabbit!
Inside the JVM - Follow the white rabbit!Sylvain Wallez
 

What's hot (20)

JVM for Dummies - OSCON 2011
JVM for Dummies - OSCON 2011JVM for Dummies - OSCON 2011
JVM for Dummies - OSCON 2011
 
Do we need Unsafe in Java?
Do we need Unsafe in Java?Do we need Unsafe in Java?
Do we need Unsafe in Java?
 
JavaOne 2011 - JVM Bytecode for Dummies
JavaOne 2011 - JVM Bytecode for DummiesJavaOne 2011 - JVM Bytecode for Dummies
JavaOne 2011 - JVM Bytecode for Dummies
 
Everything you wanted to know about Stack Traces and Heap Dumps
Everything you wanted to know about Stack Traces and Heap DumpsEverything you wanted to know about Stack Traces and Heap Dumps
Everything you wanted to know about Stack Traces and Heap Dumps
 
JRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVMJRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVM
 
Down to Stack Traces, up from Heap Dumps
Down to Stack Traces, up from Heap DumpsDown to Stack Traces, up from Heap Dumps
Down to Stack Traces, up from Heap Dumps
 
The Art of JVM Profiling
The Art of JVM ProfilingThe Art of JVM Profiling
The Art of JVM Profiling
 
JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015
 
Mastering Java ByteCode
Mastering Java ByteCodeMastering Java ByteCode
Mastering Java ByteCode
 
Everything is Permitted: Extending Built-ins
Everything is Permitted: Extending Built-insEverything is Permitted: Extending Built-ins
Everything is Permitted: Extending Built-ins
 
Unleash your inner console cowboy
Unleash your inner console cowboyUnleash your inner console cowboy
Unleash your inner console cowboy
 
Why GC is eating all my CPU?
Why GC is eating all my CPU?Why GC is eating all my CPU?
Why GC is eating all my CPU?
 
Oscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast LaneOscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast Lane
 
Python在豆瓣的应用
Python在豆瓣的应用Python在豆瓣的应用
Python在豆瓣的应用
 
Building High Performance Android Applications in Java and C++
Building High Performance Android Applications in Java and C++Building High Performance Android Applications in Java and C++
Building High Performance Android Applications in Java and C++
 
Building a java tracer
Building a java tracerBuilding a java tracer
Building a java tracer
 
Mastering java bytecode with ASM - GeeCON 2012
Mastering java bytecode with ASM - GeeCON 2012Mastering java bytecode with ASM - GeeCON 2012
Mastering java bytecode with ASM - GeeCON 2012
 
Rust tutorial from Boston Meetup 2015-07-22
Rust tutorial from Boston Meetup 2015-07-22Rust tutorial from Boston Meetup 2015-07-22
Rust tutorial from Boston Meetup 2015-07-22
 
Silicon Valley JUG: JVM Mechanics
Silicon Valley JUG: JVM MechanicsSilicon Valley JUG: JVM Mechanics
Silicon Valley JUG: JVM Mechanics
 
Inside the JVM - Follow the white rabbit!
Inside the JVM - Follow the white rabbit!Inside the JVM - Follow the white rabbit!
Inside the JVM - Follow the white rabbit!
 

Similar to Down the Rabbit Hole: Exploring Java Bytecode and JVM Optimization

Topic2JavaBasics.ppt
Topic2JavaBasics.pptTopic2JavaBasics.ppt
Topic2JavaBasics.pptMENACE4
 
hallleuah_java.ppt
hallleuah_java.ppthallleuah_java.ppt
hallleuah_java.pptRahul201258
 
The genesis of clusterlib - An open source library to tame your favourite sup...
The genesis of clusterlib - An open source library to tame your favourite sup...The genesis of clusterlib - An open source library to tame your favourite sup...
The genesis of clusterlib - An open source library to tame your favourite sup...Arnaud Joly
 
"The OpenCV Open Source Computer Vision Library: Latest Developments," a Pres...
"The OpenCV Open Source Computer Vision Library: Latest Developments," a Pres..."The OpenCV Open Source Computer Vision Library: Latest Developments," a Pres...
"The OpenCV Open Source Computer Vision Library: Latest Developments," a Pres...Edge AI and Vision Alliance
 
How to lock a Python in a cage? Managing Python environment inside an R project
How to lock a Python in a cage?  Managing Python environment inside an R projectHow to lock a Python in a cage?  Managing Python environment inside an R project
How to lock a Python in a cage? Managing Python environment inside an R projectWLOG Solutions
 
Back to the future with Java 7 (Geekout June/2011)
Back to the future with Java 7 (Geekout June/2011)Back to the future with Java 7 (Geekout June/2011)
Back to the future with Java 7 (Geekout June/2011)Martijn Verburg
 
Breaking Dependencies Legacy Code - Cork Software Crafters - September 2019
Breaking Dependencies Legacy Code -  Cork Software Crafters - September 2019Breaking Dependencies Legacy Code -  Cork Software Crafters - September 2019
Breaking Dependencies Legacy Code - Cork Software Crafters - September 2019Paulo Clavijo
 
Leveraging zeromq for node.js
Leveraging zeromq for node.jsLeveraging zeromq for node.js
Leveraging zeromq for node.jsRuben Tan
 
Threaded Programming
Threaded ProgrammingThreaded Programming
Threaded ProgrammingSri Prasanna
 
I/O (imput/output) [JAVA]
I/O  (imput/output) [JAVA]I/O  (imput/output) [JAVA]
I/O (imput/output) [JAVA]Hack '
 
CBDW2014 - MockBox, get ready to mock your socks off!
CBDW2014 - MockBox, get ready to mock your socks off!CBDW2014 - MockBox, get ready to mock your socks off!
CBDW2014 - MockBox, get ready to mock your socks off!Ortus Solutions, Corp
 
Core java over view basics introduction by quontra solutions
Core java over view basics introduction by quontra solutionsCore java over view basics introduction by quontra solutions
Core java over view basics introduction by quontra solutionsQUONTRASOLUTIONS
 
Welcome to ClojureScript
Welcome to ClojureScriptWelcome to ClojureScript
Welcome to ClojureScriptIkuru Kanuma
 
Static code analysis: what? how? why?
Static code analysis: what? how? why?Static code analysis: what? how? why?
Static code analysis: what? how? why?Andrey Karpov
 
Introduction to Kotlin Language and its application to Android platform
Introduction to Kotlin Language and its application to Android platformIntroduction to Kotlin Language and its application to Android platform
Introduction to Kotlin Language and its application to Android platformEastBanc Tachnologies
 

Similar to Down the Rabbit Hole: Exploring Java Bytecode and JVM Optimization (20)

Topic2JavaBasics.ppt
Topic2JavaBasics.pptTopic2JavaBasics.ppt
Topic2JavaBasics.ppt
 
hallleuah_java.ppt
hallleuah_java.ppthallleuah_java.ppt
hallleuah_java.ppt
 
2.ppt
2.ppt2.ppt
2.ppt
 
JAVA BASICS
JAVA BASICSJAVA BASICS
JAVA BASICS
 
The genesis of clusterlib - An open source library to tame your favourite sup...
The genesis of clusterlib - An open source library to tame your favourite sup...The genesis of clusterlib - An open source library to tame your favourite sup...
The genesis of clusterlib - An open source library to tame your favourite sup...
 
"The OpenCV Open Source Computer Vision Library: Latest Developments," a Pres...
"The OpenCV Open Source Computer Vision Library: Latest Developments," a Pres..."The OpenCV Open Source Computer Vision Library: Latest Developments," a Pres...
"The OpenCV Open Source Computer Vision Library: Latest Developments," a Pres...
 
How to lock a Python in a cage? Managing Python environment inside an R project
How to lock a Python in a cage?  Managing Python environment inside an R projectHow to lock a Python in a cage?  Managing Python environment inside an R project
How to lock a Python in a cage? Managing Python environment inside an R project
 
Clojure And Swing
Clojure And SwingClojure And Swing
Clojure And Swing
 
Back to the future with Java 7 (Geekout June/2011)
Back to the future with Java 7 (Geekout June/2011)Back to the future with Java 7 (Geekout June/2011)
Back to the future with Java 7 (Geekout June/2011)
 
Breaking Dependencies Legacy Code - Cork Software Crafters - September 2019
Breaking Dependencies Legacy Code -  Cork Software Crafters - September 2019Breaking Dependencies Legacy Code -  Cork Software Crafters - September 2019
Breaking Dependencies Legacy Code - Cork Software Crafters - September 2019
 
Leveraging zeromq for node.js
Leveraging zeromq for node.jsLeveraging zeromq for node.js
Leveraging zeromq for node.js
 
Threaded Programming
Threaded ProgrammingThreaded Programming
Threaded Programming
 
Java Programming
Java ProgrammingJava Programming
Java Programming
 
I/O (imput/output) [JAVA]
I/O  (imput/output) [JAVA]I/O  (imput/output) [JAVA]
I/O (imput/output) [JAVA]
 
CBDW2014 - MockBox, get ready to mock your socks off!
CBDW2014 - MockBox, get ready to mock your socks off!CBDW2014 - MockBox, get ready to mock your socks off!
CBDW2014 - MockBox, get ready to mock your socks off!
 
Core java over view basics introduction by quontra solutions
Core java over view basics introduction by quontra solutionsCore java over view basics introduction by quontra solutions
Core java over view basics introduction by quontra solutions
 
Welcome to ClojureScript
Welcome to ClojureScriptWelcome to ClojureScript
Welcome to ClojureScript
 
Static code analysis: what? how? why?
Static code analysis: what? how? why?Static code analysis: what? how? why?
Static code analysis: what? how? why?
 
Spock Framework
Spock FrameworkSpock Framework
Spock Framework
 
Introduction to Kotlin Language and its application to Android platform
Introduction to Kotlin Language and its application to Android platformIntroduction to Kotlin Language and its application to Android platform
Introduction to Kotlin Language and its application to Android platform
 

More from Charles Nutter

The Year of JRuby - RubyC 2018
The Year of JRuby - RubyC 2018The Year of JRuby - RubyC 2018
The Year of JRuby - RubyC 2018Charles Nutter
 
Open Source Software Needs You!
Open Source Software Needs You!Open Source Software Needs You!
Open Source Software Needs You!Charles Nutter
 
InvokeBinder: Fluent Programming for Method Handles
InvokeBinder: Fluent Programming for Method HandlesInvokeBinder: Fluent Programming for Method Handles
InvokeBinder: Fluent Programming for Method HandlesCharles Nutter
 
Over 9000: JRuby in 2015
Over 9000: JRuby in 2015Over 9000: JRuby in 2015
Over 9000: JRuby in 2015Charles Nutter
 
Doing Open Source the Right Way
Doing Open Source the Right WayDoing Open Source the Right Way
Doing Open Source the Right WayCharles Nutter
 
Bringing Concurrency to Ruby - RubyConf India 2014
Bringing Concurrency to Ruby - RubyConf India 2014Bringing Concurrency to Ruby - RubyConf India 2014
Bringing Concurrency to Ruby - RubyConf India 2014Charles Nutter
 
Beyond JVM - YOW! Brisbane 2013
Beyond JVM - YOW! Brisbane 2013Beyond JVM - YOW! Brisbane 2013
Beyond JVM - YOW! Brisbane 2013Charles Nutter
 
Beyond JVM - YOW Melbourne 2013
Beyond JVM - YOW Melbourne 2013Beyond JVM - YOW Melbourne 2013
Beyond JVM - YOW Melbourne 2013Charles Nutter
 
The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013Charles Nutter
 
High Performance Ruby - E4E Conference 2013
High Performance Ruby - E4E Conference 2013High Performance Ruby - E4E Conference 2013
High Performance Ruby - E4E Conference 2013Charles Nutter
 
Invokedynamic in 45 Minutes
Invokedynamic in 45 MinutesInvokedynamic in 45 Minutes
Invokedynamic in 45 MinutesCharles Nutter
 
Invokedynamic: Tales from the Trenches
Invokedynamic: Tales from the TrenchesInvokedynamic: Tales from the Trenches
Invokedynamic: Tales from the TrenchesCharles Nutter
 
Why JRuby? - RubyConf 2012
Why JRuby? - RubyConf 2012Why JRuby? - RubyConf 2012
Why JRuby? - RubyConf 2012Charles Nutter
 
Aloha RubyConf 2012 - JRuby
Aloha RubyConf 2012 - JRubyAloha RubyConf 2012 - JRuby
Aloha RubyConf 2012 - JRubyCharles Nutter
 
High Performance Ruby - Golden Gate RubyConf 2012
High Performance Ruby - Golden Gate RubyConf 2012High Performance Ruby - Golden Gate RubyConf 2012
High Performance Ruby - Golden Gate RubyConf 2012Charles Nutter
 
InvokeDynamic - You Ain't Seen Nothin Yet
InvokeDynamic - You Ain't Seen Nothin YetInvokeDynamic - You Ain't Seen Nothin Yet
InvokeDynamic - You Ain't Seen Nothin YetCharles Nutter
 
Building Languages for the JVM - StarTechConf 2011
Building Languages for the JVM - StarTechConf 2011Building Languages for the JVM - StarTechConf 2011
Building Languages for the JVM - StarTechConf 2011Charles Nutter
 
JRuby: What's Different (RORO Melbourne October 2011)
JRuby: What's Different (RORO Melbourne October 2011)JRuby: What's Different (RORO Melbourne October 2011)
JRuby: What's Different (RORO Melbourne October 2011)Charles Nutter
 

More from Charles Nutter (20)

The Year of JRuby - RubyC 2018
The Year of JRuby - RubyC 2018The Year of JRuby - RubyC 2018
The Year of JRuby - RubyC 2018
 
Open Source Software Needs You!
Open Source Software Needs You!Open Source Software Needs You!
Open Source Software Needs You!
 
InvokeBinder: Fluent Programming for Method Handles
InvokeBinder: Fluent Programming for Method HandlesInvokeBinder: Fluent Programming for Method Handles
InvokeBinder: Fluent Programming for Method Handles
 
Over 9000: JRuby in 2015
Over 9000: JRuby in 2015Over 9000: JRuby in 2015
Over 9000: JRuby in 2015
 
Doing Open Source the Right Way
Doing Open Source the Right WayDoing Open Source the Right Way
Doing Open Source the Right Way
 
JRuby: The Hard Parts
JRuby: The Hard PartsJRuby: The Hard Parts
JRuby: The Hard Parts
 
Bringing Concurrency to Ruby - RubyConf India 2014
Bringing Concurrency to Ruby - RubyConf India 2014Bringing Concurrency to Ruby - RubyConf India 2014
Bringing Concurrency to Ruby - RubyConf India 2014
 
Beyond JVM - YOW! Brisbane 2013
Beyond JVM - YOW! Brisbane 2013Beyond JVM - YOW! Brisbane 2013
Beyond JVM - YOW! Brisbane 2013
 
Beyond JVM - YOW Melbourne 2013
Beyond JVM - YOW Melbourne 2013Beyond JVM - YOW Melbourne 2013
Beyond JVM - YOW Melbourne 2013
 
The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013
 
High Performance Ruby - E4E Conference 2013
High Performance Ruby - E4E Conference 2013High Performance Ruby - E4E Conference 2013
High Performance Ruby - E4E Conference 2013
 
Invokedynamic in 45 Minutes
Invokedynamic in 45 MinutesInvokedynamic in 45 Minutes
Invokedynamic in 45 Minutes
 
Invokedynamic: Tales from the Trenches
Invokedynamic: Tales from the TrenchesInvokedynamic: Tales from the Trenches
Invokedynamic: Tales from the Trenches
 
Why JRuby? - RubyConf 2012
Why JRuby? - RubyConf 2012Why JRuby? - RubyConf 2012
Why JRuby? - RubyConf 2012
 
Aloha RubyConf 2012 - JRuby
Aloha RubyConf 2012 - JRubyAloha RubyConf 2012 - JRuby
Aloha RubyConf 2012 - JRuby
 
High Performance Ruby - Golden Gate RubyConf 2012
High Performance Ruby - Golden Gate RubyConf 2012High Performance Ruby - Golden Gate RubyConf 2012
High Performance Ruby - Golden Gate RubyConf 2012
 
Euruko 2012 - JRuby
Euruko 2012 - JRubyEuruko 2012 - JRuby
Euruko 2012 - JRuby
 
InvokeDynamic - You Ain't Seen Nothin Yet
InvokeDynamic - You Ain't Seen Nothin YetInvokeDynamic - You Ain't Seen Nothin Yet
InvokeDynamic - You Ain't Seen Nothin Yet
 
Building Languages for the JVM - StarTechConf 2011
Building Languages for the JVM - StarTechConf 2011Building Languages for the JVM - StarTechConf 2011
Building Languages for the JVM - StarTechConf 2011
 
JRuby: What's Different (RORO Melbourne October 2011)
JRuby: What's Different (RORO Melbourne October 2011)JRuby: What's Different (RORO Melbourne October 2011)
JRuby: What's Different (RORO Melbourne October 2011)
 

Recently uploaded

Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Strongerpanagenda
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsRavi Sanghani
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterMydbops
 
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...AliaaTarek5
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityIES VE
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...panagenda
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch TuesdayIvanti
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Scott Andery
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demoHarshalMandlekar2
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentPim van der Noll
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfNeo4j
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 

Recently uploaded (20)

Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and Insights
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL Router
 
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a reality
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch Tuesday
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demo
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdf
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 

Down the Rabbit Hole: Exploring Java Bytecode and JVM Optimization

  • 1. Down the Rabbit Hole An adventure in JVM wonderland Monday, September 30, 13
  • 2. Me • Charles Oliver Nutter • Red Hat (yes, I have one; no, I don’t wear it) • JRuby and JVM languages • JVM hacking and spelunking • @headius Monday, September 30, 13
  • 3. What are we going to do today? • Look at some interesting Java features • See how they’re compiled to bytecode • Watch what the JVM does with them • Examine the actual native code they become Monday, September 30, 13
  • 5. Who AreYou? • Java developers? • Performance engineers? • Debuggers? • All of the above? Monday, September 30, 13
  • 6. Details Matter • Cool features with hidden costs • Inner classes • Structural types in Scala • Serialization • How code design impacts performance • What JVM can and can’t do for you Monday, September 30, 13
  • 7. Sufficiently Smart Compiler “HighLevelLanguage H may be slower than the LowLevelLanguage L, but given a SufficientlySmartCompiler this would not be the case” http://c2.com/cgi/wiki?SufficientlySmartCompiler Monday, September 30, 13
  • 8. Sufficiently Smart Compiler If you wait long enough*, the JVM will eventually optimize everything perfectly and even terrible code will perform well. * for some definition of “long” Monday, September 30, 13
  • 9. Part One:The Primer Monday, September 30, 13
  • 10. Vocabulary • Source • The .java text that represents a program • Bytecode • The binary version of the program that all JVMs can load and execute Monday, September 30, 13
  • 11. Vocabulary • Native code • Machine code specific to the current platform (OS, CPU) that represents the program in a form the CPU can execute directly • Heap • The JVM-controlled area of memory where Java objects live Monday, September 30, 13
  • 12. Vocabulary • JIT • “Just In Time” (compilation) that turns one program form into a lower program form, e.g. bytecode into native code at runtime • AOT • Compilation that occurs before runtime Monday, September 30, 13
  • 13. JVM 101 Java source JVM bytecode javac JVM bytecode Bytecode interpreter runs inside gather information JIT compiler triggers Native code produces executes backs off Monday, September 30, 13
  • 14. Vocabulary • Inlining • Inserting the code of a called method into the caller, avoiding overhead of the call and optimizing the two together • Optimization • Doing the least amount of work needed to accomplish some goal Monday, September 30, 13
  • 15. Inlining Instance Method Load target and arguments Target type is same? Method lookup Run target code directly Yes No Run target method as a call Monday, September 30, 13
  • 16. Inlining Static or Special Method Load arguments Run target code directly Monday, September 30, 13
  • 17. Our Tools • javac, obviously • javap to dump .class data • -XX:+PrintCompilation • -XX:+PrintInlining • -XX:+PrintAssembly Monday, September 30, 13
  • 18. Hello, world! • We’ll start with something simple. Monday, September 30, 13
  • 19. package com.headius.talks.rabbithole; public class HelloWorld {     public static void main(String[] args) {         System.out.println("Hello, world!");     } } Monday, September 30, 13
  • 20. Level 1: Bytecode • javap • Java class file disassembler • Dump structure, data, metadata, and code Monday, September 30, 13
  • 21. $ javap -cp dist/RabbitHole.jar com.headius.talks.rabbithole.HelloWorld Compiled from "HelloWorld.java" public class com.headius.talks.rabbithole.HelloWorld { public com.headius.talks.rabbithole.HelloWorld(); public static void main(java.lang.String[]); } Monday, September 30, 13
  • 22. $ javap -cp dist/RabbitHole.jar -c com.headius.talks.rabbithole.HelloWorld Compiled from "HelloWorld.java" public class com.headius.talks.rabbithole.HelloWorld { ... 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 8: return } Monday, September 30, 13
  • 23. Our First Bytecodes • getstatic/putstatic - static field access • ldc - load constant value on stack • invokevirtual - call a concrete instance method • return - return from a void method Monday, September 30, 13
  • 24. $ javap -cp dist/RabbitHole.jar -c com.headius.talks.rabbithole.HelloWorld Compiled from "HelloWorld.java" public class com.headius.talks.rabbithole.HelloWorld { ... 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 8: return } Monday, September 30, 13
  • 25. Level 2: Compiler Logs • -XX:+PrintCompilation • Display methods as they compile • -XX:+PrintInlining • Display inlined methods as nested Monday, September 30, 13
  • 26. JVM JIT • Code is interpreted first • After some threshold, JIT fires • Classic JVM went straight to “client” or “server” • Tiered compiler goes to “client plus profiling” and later “server” Monday, September 30, 13
  • 27. public class HelloWorld {     public static void main(String[] args) {         for (int i = 0; i < 100000; i++) {             hello();         }     }          private static void hello() {         System.err.println("Hello, world!");     } } Monday, September 30, 13
  • 28. $ java -Xbatch -XX:-TieredCompilation -XX:+PrintCompilation -cp dist/RabbitHole.jar com.headius.talks.rabbithole.HelloWorld 2> /dev/null Monday, September 30, 13
  • 29. 83 1 java.lang.String::hashCode (55 bytes) 91 2 java.lang.String::indexOf (70 bytes) 121 3 sun.nio.cs.UTF_8$Encoder::encodeArrayLoop (489 bytes) 137 4 java.nio.Buffer::position (5 bytes) ... 283 47 java.lang.String::indexOf (7 bytes) 285 48 com.headius.talks.rabbithole.HelloWorld::hello (9 bytes) 285 49 ! java.io.PrintStream::println (24 bytes) 295 50 java.io.PrintStream::print (13 bytes) 296 51 ! java.io.PrintStream::write (83 bytes) 301 52 ! java.io.PrintStream::newLine (73 bytes) 302 53 java.io.BufferedWriter::newLine (9 bytes) 302 54 % com.headius.talks.rabbithole.HelloWorld::main @ 2 (18 bytes) Monday, September 30, 13
  • 30. 83 1 java.lang.String::hashCode (55 bytes) 91 2 java.lang.String::indexOf (70 bytes) 121 3 sun.nio.cs.UTF_8$Encoder::encodeArrayLoop (489 bytes) 137 4 java.nio.Buffer::position (5 bytes) ... 283 47 java.lang.String::indexOf (7 bytes) 285 48 com.headius.talks.rabbithole.HelloWorld::hello (9 bytes) 285 49 ! java.io.PrintStream::println (24 bytes) 295 50 java.io.PrintStream::print (13 bytes) 296 51 ! java.io.PrintStream::write (83 bytes) 301 52 ! java.io.PrintStream::newLine (73 bytes) 302 53 java.io.BufferedWriter::newLine (9 bytes) 302 54 % com.headius.talks.rabbithole.HelloWorld::main @ 2 (18 bytes) Monday, September 30, 13
  • 31. $ java -Xbatch -XX:-TieredCompilation -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining -cp dist/RabbitHole.jar com.headius.talks.rabbithole.HelloWorld 2> /dev/null Monday, September 30, 13
  • 32. 82 1 b java.lang.String::hashCode (55 bytes) 94 2 b java.lang.String::indexOf (70 bytes) @ 66 java.lang.String::indexOfSupplementary (71 bytes) too big 132 3 b sun.nio.cs.UTF_8$Encoder::encodeArrayLoop (489 bytes) @ 1 java.nio.CharBuffer::array (35 bytes) inline (hot) @ 6 java.nio.CharBuffer::arrayOffset (35 bytes) inline (hot) ... 397 48 b com.headius.talks.rabbithole.HelloWorld::hello (9 bytes) !m @ 5 java.io.PrintStream::println (24 bytes) inline (hot) @ 6 java.io.PrintStream::print (13 bytes) inline (hot) ... 446 54 % b com.headius.talks.rabbithole.HelloWorld::main @ 2 (18 bytes) @ 8 com.headius.talks.rabbithole.HelloWorld::hello (9 bytes) already compiled into a big method Monday, September 30, 13
  • 33. 82 1 b java.lang.String::hashCode (55 bytes) 94 2 b java.lang.String::indexOf (70 bytes) @ 66 java.lang.String::indexOfSupplementary (71 bytes) too big 132 3 b sun.nio.cs.UTF_8$Encoder::encodeArrayLoop (489 bytes) @ 1 java.nio.CharBuffer::array (35 bytes) inline (hot) @ 6 java.nio.CharBuffer::arrayOffset (35 bytes) inline (hot) ... 397 48 b com.headius.talks.rabbithole.HelloWorld::hello (9 bytes) !m @ 5 java.io.PrintStream::println (24 bytes) inline (hot) @ 6 java.io.PrintStream::print (13 bytes) inline (hot) ... 446 54 % b com.headius.talks.rabbithole.HelloWorld::main @ 2 (18 bytes) @ 8 com.headius.talks.rabbithole.HelloWorld::hello (9 bytes) already compiled into a big method Monday, September 30, 13
  • 34. Level 3: Native Code • -XX:+PrintAssembly • Dumps “human readable” JITed code • Google for “hotspot printassembly” • Aren’t you excited?! Monday, September 30, 13
  • 35. $ java -Xbatch -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -cp dist/RabbitHole.jar com.headius.talks.rabbithole.HelloWorld 2> /dev/null | less Monday, September 30, 13
  • 36. Decoding compiled method 0x0000000110526110: Code: [Entry Point] [Verified Entry Point] [Constants] # {method} {0x00000001100a6420} 'hello' '()V' in 'com/headius/talks/rabbithole/HelloWorld' # [sp+0x70] (sp of caller) 0x0000000110526300: mov %eax,-0x14000(%rsp) 0x0000000110526307: push %rbp 0x0000000110526308: sub $0x60,%rsp ;*synchronization entry ; - com.headius.talks.rabbithole.HelloWorld::hello@-1 (line 13) 0x000000011052630c: movabs $0x7aaa80c78,%r10 ; {oop(a 'java/lang/Class' = 'java/lang/System')} 0x0000000110526316: mov 0x70(%r10),%r11d ;*getstatic err ; - com.headius.talks.rabbithole.HelloWorld::hello@0 (line 13) 0x000000011052631a: mov %r11d,0x10(%rsp) 0x000000011052631f: test %r11d,%r11d 0x0000000110526322: je 0x000000011052664e ;*invokevirtual println ; - com.headius.talks.rabbithole.HelloWorld::hello@5 (line 13) Monday, September 30, 13
  • 37. Too big! • Server produces ~2700 bytes of ASM • Client produces ~594 bytes of ASM • Most of server output is from inlining • More profiling, more code, more perf • ...and slower startup Monday, September 30, 13
  • 38. public class Tiny1 {     public static void main(String[] args) {         for (int i = 0; i < 100000; i++) {             tiny();         }     }          public static int tiny() {         return 1 + 1;     } } Monday, September 30, 13
  • 39. public static int tiny(); Code: 0: iconst_2 1: ireturn iconst_2: load integer 2 on stack ireturn: return int Monday, September 30, 13
  • 40. 110 3 b com.headius.talks.rabbithole.Tiny1::tiny (2 bytes) 111 4 % b com.headius.talks.rabbithole.Tiny1::main @ 2 (19 bytes) @ 8 com.headius.talks.rabbithole.Tiny1::tiny (2 bytes) inline (hot) Monday, September 30, 13
  • 41. {0x000000010994c3c0} 'tiny' '()I' in 'com/headius/talks/rabbithole/Tiny1' # [sp+0x40] (sp of caller) 0x0000000109e566a0: mov %eax,-0x14000(%rsp) 0x0000000109e566a7: push %rbp 0x0000000109e566a8: sub $0x30,%rsp ;*iconst_2 ; - com.headius.talks.rabbithole.Tiny1::tiny@0 (line 11) 0x0000000109e566ac: mov $0x2,%eax 0x0000000109e566b1: add $0x30,%rsp 0x0000000109e566b5: pop %rbp 0x0000000109e566b6: test %eax,-0x9a05bc(%rip) # 0x00000001094b6100 ; {poll_return} 0x0000000109e566bc: retq Monday, September 30, 13
  • 42. {0x000000010994c3c0} 'tiny' '()I' in 'com/headius/talks/rabbithole/Tiny1' # [sp+0x40] (sp of caller) 0x0000000109e566a0: mov %eax,-0x14000(%rsp) 0x0000000109e566a7: push %rbp 0x0000000109e566a8: sub $0x30,%rsp ;*iconst_2 ; - com.headius.talks.rabbithole.Tiny1::tiny@0 (line 11) 0x0000000109e566ac: mov $0x2,%eax 0x0000000109e566b1: add $0x30,%rsp 0x0000000109e566b5: pop %rbp 0x0000000109e566b6: test %eax,-0x9a05bc(%rip) # 0x00000001094b6100 ; {poll_return} 0x0000000109e566bc: retq Monday, September 30, 13
  • 43. {0x000000010e67d300} 'main' '([Ljava/lang/String;)V' in 'com/headius/talks/rabbithole/Tiny1' 0x000000010eb879a0: mov %eax,-0x14000(%rsp) 0x000000010eb879a7: push %rbp 0x000000010eb879a8: sub $0x40,%rsp ;*iconst_0 ; - com.headius.talks.rabbithole.Tiny1::main@0 (line 5) 0x000000010eb879ac: mov $0x0,%esi 0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1 ; - com.headius.talks.rabbithole.Tiny1::main@2 (line 5) 0x000000010eb879b6: xchg %ax,%ax 0x000000010eb879b8: inc %esi ; OopMap{off=26} ;*goto ; - com.headius.talks.rabbithole.Tiny1::main@15 (line 5) 0x000000010eb879ba: test %eax,-0x9a08c0(%rip) # 0x000000010e1e7100 ;*goto ; - com.headius.talks.rabbithole.Tiny1::main@15 (line 5) ; {poll} 0x000000010eb879c0: cmp $0x186a0,%esi 0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge ; - com.headius.talks.rabbithole.Tiny1::main@5 (line 5) 0x000000010eb879c8: add $0x40,%rsp 0x000000010eb879cc: pop %rbp 0x000000010eb879cd: test %eax,-0x9a08d3(%rip) # 0x000000010e1e7100 ; {poll_return} 0x000000010eb879d3: retq ;*return ; - com.headius.talks.rabbithole.Tiny1::main@18 (line 8) Monday, September 30, 13
  • 44. 0x000000010eb879a0: mov %eax,-0x14000(%rsp) 0x000000010eb879a7: push %rbp 0x000000010eb879a8: sub $0x40,%rsp ;*iconst_0 0x000000010eb879ac: mov $0x0,%esi 0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1 0x000000010eb879b6: xchg %ax,%ax 0x000000010eb879b8: inc %esi ; OopMap{off=26} 0x000000010eb879ba: test %eax,-0x9a08c0(%rip) # 0x000000010e1e7100 0x000000010eb879c0: cmp $0x186a0,%esi 0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge 0x000000010eb879c8: add $0x40,%rsp 0x000000010eb879cc: pop %rbp 0x000000010eb879cd: test %eax,-0x9a08d3(%rip) # 0x000000010e1e7100 0x000000010eb879d3: retq ;*return Monday, September 30, 13
  • 45. 0x000000010eb879a0: mov %eax,-0x14000(%rsp) 0x000000010eb879a7: push %rbp 0x000000010eb879a8: sub $0x40,%rsp ;*iconst_0 0x000000010eb879ac: mov $0x0,%esi 0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1 0x000000010eb879b6: xchg %ax,%ax 0x000000010eb879b8: inc %esi ; OopMap{off=26} 0x000000010eb879ba: test %eax,-0x9a08c0(%rip) # 0x000000010e1e7100 0x000000010eb879c0: cmp $0x186a0,%esi 0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge 0x000000010eb879c8: add $0x40,%rsp 0x000000010eb879cc: pop %rbp 0x000000010eb879cd: test %eax,-0x9a08d3(%rip) # 0x000000010e1e7100 0x000000010eb879d3: retq ;*return Monday, September 30, 13
  • 46. 0x000000010eb879ac: mov $0x0,%esi 0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1 0x000000010eb879b6: xchg %ax,%ax 0x000000010eb879b8: inc %esi ; OopMap{off=26} 0x000000010eb879ba: test %eax,-0x9a08c0(%rip) # 0x000000010e1e7100 0x000000010eb879c0: cmp $0x186a0,%esi 0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge 0x000000010eb879cd: test %eax,-0x9a08d3(%rip) # 0x000000010e1e7100 0x000000010eb879d3: retq ;*return Monday, September 30, 13
  • 47. 0x000000010eb879ac: mov $0x0,%esi 0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1 0x000000010eb879b6: xchg %ax,%ax 0x000000010eb879b8: inc %esi ; OopMap{off=26} 0x000000010eb879ba: test %eax,-0x9a08c0(%rip) # 0x000000010e1e7100 0x000000010eb879c0: cmp $0x186a0,%esi 0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge 0x000000010eb879cd: test %eax,-0x9a08d3(%rip) # 0x000000010e1e7100 0x000000010eb879d3: retq ;*return Monday, September 30, 13
  • 48. 0x000000010eb879ac: mov $0x0,%esi 0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1 0x000000010eb879b6: xchg %ax,%ax 0x000000010eb879b8: inc %esi ; OopMap{off=26} 0x000000010eb879c0: cmp $0x186a0,%esi 0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge 0x000000010eb879d3: retq ;*return Monday, September 30, 13
  • 49. 0x000000010eb879ac: mov $0x0,%esi 0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1 0x000000010eb879b6: xchg %ax,%ax 0x000000010eb879b8: inc %esi ; OopMap{off=26} 0x000000010eb879c0: cmp $0x186a0,%esi 0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge 0x000000010eb879d3: retq ;*return Monday, September 30, 13
  • 50. 0x000000010eb879ac: mov $0x0,%esi 0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1 0x000000010eb879b8: inc %esi ; OopMap{off=26} 0x000000010eb879c0: cmp $0x186a0,%esi 0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge 0x000000010eb879d3: retq ;*return Monday, September 30, 13
  • 51. 1: mov $0,%esi 2: jmpq 4: 3: inc %esi 4: cmp $1000000,%esi 5: jl 3: 6: retq Monday, September 30, 13
  • 53. It’s not that hard once you know what to look at. Monday, September 30, 13
  • 54. Part 2:The Fun Stuff Monday, September 30, 13
  • 55. Java Features • final fields • synchronized • string switch • lambda Monday, September 30, 13
  • 56. #1: Final Fields • Final fields can’t be modified • The pipeline can take advantage • ...but it doesn’t always Monday, September 30, 13
  • 57. public class Fields {     private static final String MY_STRING = "This is a static string";     private static final String MY_PROPERTY = System.getProperty("java.home");          public static void main(String[] args) {         System.out.println(MY_STRING);         System.out.println(MY_PROPERTY); } } Monday, September 30, 13
  • 58. public static void main(java.lang.String[]); Code: 0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #9 // String This is a static string 5: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream; 11: getstatic #11 // Field MY_PROPERTY:Ljava/lang/String; 14: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V     private static final String MY_STRING = "This is a static string";     private static final String MY_PROPERTY = System.getProperty("java.home"); Monday, September 30, 13
  • 59.     private static int addHashes() {         return MY_STRING.hashCode() + MY_PROPERTY.hashCode();     } Monday, September 30, 13
  • 60. movabs $0x7aab6c4f8,%r10 ; {oop("This is a static string")} mov %eax,0x10(%r10) ;*iload_1 ; - String::hashCode@53 (line 1467) ; - Fields::addHashes@2 (line 36) movabs $0x7aaa97a98,%rcx ; {oop(".../jdk1.8.0.jdk/Contents/Home/jre")} mov 0x10(%rcx),%r10d ;*getfield hash ; - String::hashCode@1 (line 1458) ; - Fields::addHashes@8 (line 36) Monday, September 30, 13
  • 61.     private final String myString = "This is an instance string";     private final String myProperty = System.getProperty("java.home");     public int addHashes2() {         return myString.hashCode() + myProperty.hashCode();     }     Monday, September 30, 13
  • 62. private int addHashes2(); Code: 0: ldc #2 // String This is an instance string 2: invokevirtual #18 // Method java/lang/String.hashCode:()I 5: aload_0 6: getfield #6 // Field myProperty:Ljava/lang/String; 9: invokevirtual #18 // Method java/lang/String.hashCode:()I 12: iadd 13: ireturn Monday, September 30, 13
  • 63. movabs $0x7aab6d318,%rcx ; {oop("This is an instance string")} mov 0x10(%rcx),%r10d ;*getfield hash ; - String::hashCode@1 (line 1458) ; - Fields::addHashes2@2 (line 40) Monday, September 30, 13
  • 64. mov 0x10(%rsi),%ecx ;*getfield myProperty ; - Fields::addHashes2@6 (line 40) mov 0x10(%r12,%rcx,8),%eax ;*getfield hash ; - String::hashCode@1 (line 1458) ; - Fields::addHashes2@9 (line 40) Monday, September 30, 13
  • 65. ACHIEVEMENT UNLOCKED: Find something Hotspot could do better Monday, September 30, 13
  • 66. #2: Concurrency Stuff • What does “synchronized” do? • What does “volatile” do? Monday, September 30, 13
  • 67. public class Concurrency {     public static void main(String[] args) {         System.out.println(getTime());         System.out.println(getTimeSynchronized());     }          public static long getTime() {         return System.currentTimeMillis();     }          public static synchronized long getTimeSynchronized() {         return System.currentTimeMillis();     } } Monday, September 30, 13
  • 68. public static void main(java.lang.String[]); Code: 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: invokestatic #3 // Method getTime:()J 6: invokevirtual #4 // Method java/io/PrintStream.println:(J)V 9: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 12: invokestatic #5 // Method getTimeSynchronized:()J 15: invokevirtual #4 // Method java/io/PrintStream.println:(J)V Monday, September 30, 13
  • 69. public static long getTime(); Code: 0: invokestatic #7 // Method java/lang/System.currentTimeMillis:()J 3: lreturn public static synchronized long getTimeSynchronized(); Code: 0: invokestatic #7 // Method java/lang/System.currentTimeMillis:()J 3: lreturn Monday, September 30, 13
  • 70. 'getTime' '()J' in 'com/headius/talks/rabbithole/Concurrency' movabs $0x1015dbd3e,%r10 callq *%r10 ;*invokestatic currentTimeMillis ; - Concurrency::getTime@0 (line 22) retq Monday, September 30, 13
  • 71. 'getTime' '()J' in 'com/headius/talks/rabbithole/Concurrency' movabs $0x1015dbd3e,%r10 callq *%r10 ;*invokestatic currentTimeMillis ; - Concurrency::getTime@0 (line 22) retq Monday, September 30, 13
  • 73. movabs $0x7aab6bee8,%r10 ; {oop(a 'java/lang/Class' = '.../Concurrency')} mov (%r10),%rax mov %rax,%r10 and $0x7,%r10 cmp $0x5,%r10 jne 0x000000010ef0665f mov $0xdf3803fe,%r11d ; {metadata('java/lang/Class')} mov 0xa8(%r12,%r11,8),%r10 mov %r10,%r11 or %r15,%r11 mov %r11,%r8 xor %rax,%r8 $0xffffffffffffff87,%r8 jne 0x000000010ef068e4 mov %r14d,(%rsp) ;*synchronization entry ; - Concurrency::getTimeSynchronized@-1 (line 26) ; - Concurrency::main@58 (line 16) movabs $0x10de5ad3e,%r10 callq *%r10 ;*invokestatic currentTimeMillis ; - Concurrency::getTimeSynchronized@0 (line 26) ; - Concurrency::main@58 (line 16) Monday, September 30, 13
  • 74. movabs $0x7aab6bee8,%r10 ; {oop(a 'java/lang/Class' = '.../Concurrency')} mov (%r10),%rax mov %rax,%r10 and $0x7,%r10 cmp $0x5,%r10 jne 0x000000010ef0665f mov $0xdf3803fe,%r11d ; {metadata('java/lang/Class')} mov 0xa8(%r12,%r11,8),%r10 mov %r10,%r11 or %r15,%r11 mov %r11,%r8 xor %rax,%r8 $0xffffffffffffff87,%r8 jne 0x000000010ef068e4 mov %r14d,(%rsp) ;*synchronization entry ; - Concurrency::getTimeSynchronized@-1 (line 26) ; - Concurrency::main@58 (line 16) movabs $0x10de5ad3e,%r10 callq *%r10 ;*invokestatic currentTimeMillis ; - Concurrency::getTimeSynchronized@0 (line 26) ; - Concurrency::main@58 (line 16) Monday, September 30, 13
  • 75. Vocabulary • Lock coarsening • Expanding the use of multiple fine- grained locks into a single coarse-grained lock • Lock eliding • Eliminating locking when it will not affect the behavior of the program Monday, September 30, 13
  • 76. movabs $0x7aab6bee8,%r10 ; {oop(a 'java/lang/Class' = '.../Concurrency')} mov (%r10),%rax mov %rax,%r10 and $0x7,%r10 cmp $0x5,%r10 jne 0x000000010ef0665f mov $0xdf3803fe,%r11d ; {metadata('java/lang/Class')} mov 0xa8(%r12,%r11,8),%r10 mov %r10,%r11 or %r15,%r11 mov %r11,%r8 xor %rax,%r8 $0xffffffffffffff87,%r8 jne 0x000000010ef068e4 mov %r14d,(%rsp) ;*synchronization entry ; - Concurrency::getTimeSynchronized@-1 (line 26) ; - Concurrency::main@58 (line 16) movabs $0x10de5ad3e,%r10 callq *%r10 ;*invokestatic currentTimeMillis ; - Concurrency::getTimeSynchronized@0 (line 26) ; - Concurrency::main@58 (line 16) Monday, September 30, 13
  • 77. 0x000000010ef0665f: movabs $0x7aab6bee8,%r11 ; {oop(a 'java/lang/Class' = '.../Concurrency')} 0x000000010ef06669: lea 0x10(%rsp),%rbx 0x000000010ef0666e: mov (%r11),%rax 0x000000010ef06671: test $0x2,%eax 0x000000010ef06676: jne 0x000000010ef0669f 0x000000010ef0667c: or $0x1,%eax 0x000000010ef0667f: mov %rax,(%rbx) 0x000000010ef06682: lock cmpxchg %rbx,(%r11) 0x000000010ef06687: je 0x000000010ef066bc Monday, September 30, 13
  • 78. Volatile • Forces commit of memory • Forces code ordering • Prevents some optimizations • Similar impact to unecessary locking • ...but it can’t ever be removed Monday, September 30, 13
  • 79. 11345d823: mov 0x70(%r8),%r9d ;*getstatic NULL_OBJECT_ARRAY ; - org.jruby.RubyBasicObject::<init>@5 (line 76) ; - org.jruby.RubyObject::<init>@2 (line 118) ; - org.jruby.RubyNumeric::<init>@2 (line 111) ; - org.jruby.RubyInteger::<init>@2 (line 95) ; - org.jruby.RubyFixnum::<init>@5 (line 112) ; - org.jruby.RubyFixnum::newFixnum@25 (line 173) 11345d827: mov %r9d,0x14(%rax) 11345d82b: lock addl $0x0,(%rsp) ;*putfield varTable ; - org.jruby.RubyBasicObject::<init>@8 (line 76) ; - org.jruby.RubyObject::<init>@2 (line 118) ; - org.jruby.RubyNumeric::<init>@2 (line 111) ; - org.jruby.RubyInteger::<init>@2 (line 95) ; - org.jruby.RubyFixnum::<init>@5 (line 112) ; - org.jruby.RubyFixnum::newFixnum@25 (line 173) LOCK Code from a RubyBasicObject’s default constructor. Why are we doing a volatile write in the constructor? Wednesday, July 27, 2011 Monday, September 30, 13
  • 80. public class RubyBasicObject ... { private static final boolean DEBUG = false; private static final Object[] NULL_OBJECT_ARRAY = new Object[0]; // The class of this object protected transient RubyClass metaClass; // zeroed by jvm protected int flags; // variable table, lazily allocated as needed (if needed) private volatile Object[] varTable = NULL_OBJECT_ARRAY; LOCK Maybe it’s not such a good idea to pre-init a volatile? Wednesday, July 27, 2011 Monday, September 30, 13
  • 81. #3: String Switch • Added in Java 7 • ...and there was much rejoicing • But how does it really work? Monday, September 30, 13
  • 82. A Normal Switch • Variable switch parameter • Constant case values • Branch based on a table (fast) for narrow range of cases • Branch based on a lookup (less fast) for broad range of cases Monday, September 30, 13
  • 83. public class StringSwitch {     public static void main(String[] args) {         String count = "unknown";         switch (args.length) {             case 0: count = "zero"; break;             case 1: count = "one"; break;             case 2: count = "two"; break;         } ... Monday, September 30, 13
  • 84. public static void main(java.lang.String[]); Code: 0: ldc #2 // String unknown 2: astore_1 3: aload_0 4: arraylength 5: tableswitch { // 0 to 2 0: 32 1: 38 2: 44 default: 47 } 32: ldc #3 // String zero 34: astore_1 35: goto 47 38: ldc #4 // String one 40: astore_1 41: goto 47 44: ldc #5 // String two 46: astore_1 Monday, September 30, 13
  • 85. switch (args.length) {     case 2000000: count = "two million"; break;     case 1000000: count = "one million"; break;     case 3000000: count = "three million"; break; } Monday, September 30, 13
  • 86. 49: lookupswitch { // 3 1000000: 90 2000000: 84 3000000: 96 default: 99 } Monday, September 30, 13
  • 87. Comparison • tableswitch is O(1) • Indexed lookup of target • lookupswitch is O(log n) • Binary search for target Monday, September 30, 13
  • 88. Get to the point already! Monday, September 30, 13
  • 89. The Point • What kind of switch do we use for String? • Table doesn’t work for hashcodes • Lookup might collide • Answer: both, plus .equals() Monday, September 30, 13
  • 90.     static String chooseGreeting(String language) {         switch (language) {             case "Java": return "I love to hate you!";             case "Scala": return "I love you, I think!";             case "Clojure": return "(love I you)";             case "Groovy": return "I love ?: you";             case "Ruby": return "I.love? you # => true";             default: return "Who are you?";         }     } Monday, September 30, 13
  • 91. static java.lang.String chooseGreeting(java.lang.String); Code: 0: aload_0 1: astore_1 2: iconst_m1 3: istore_2 4: aload_1 5: invokevirtual #16 // Method java/lang/String.hashCode:()I 8: lookupswitch { // 5 -1764029756: 88 2301506: 60 2558458: 116 79698214: 74 2141368366: 102 default: 127 } Hidden int variable... Monday, September 30, 13
  • 92. 74: aload_1 75: ldc #14 // String Scala 77: invokevirtual #17 // Method String.equals:(Ljava/lang/Object;)Z 80: ifeq 127 83: iconst_1 84: istore_2 Same hidden int variable now = 1 Monday, September 30, 13
  • 93. 127: iload_2 128: tableswitch { // 0 to 4 0: 164 1: 167 2: 170 3: 173 4: 176 default: 179 } 164: ldc #20 // String I love to hate you! 166: areturn 167: ldc #21 // String I love you, I think! 169: areturn 170: ldc #22 // String (love I you) 172: areturn 173: ldc #23 // String I love ?: you 175: areturn 176: ldc #24 // String I.love? you # => true 178: areturn 179: ldc #25 // String Who are you? 181: areturn A-ha! There it is! Monday, September 30, 13
  • 94.    static String chooseGreeting2(String language) {        int hash = language.hashCode();        int target = -1;        switch (hash) {            case 2301506: if (language.equals("Java")) target = 0; break;            case 79698214: if (language.equals("Scala"))target = 1; break;            case -1764029756: if (language.equals("Clojure"))target = 2; break;            case 2141368366: if (language.equals("Groovy"))target = 3; break;            case 2558458: if (language.equals("Ruby"))target = 3; break;        }        switch (target) {            case 0: return "I love to hate you!";            case 1: return "I love you, I think!";            case 2: return "(love I you)";            case 3: return "I love ?: you";            case 4: return "I.love? you # => true";            default: return "Who are you?";        }    } Monday, September 30, 13
  • 95. It’s just a hash table! Monday, September 30, 13
  • 96. #4: Lambda Expressions • New for Java 8 • ...and there was much rejoicing • Key goals • Lighter-weight than inner classes • No class-per-lambda • Optimizable by JVM Monday, September 30, 13
  • 97. public class LambdaStuff {     public static void main(String[] args) {         List<String> list = Arrays.asList(                 "Clojure",                 "Java",                 "Ruby",                 "Groovy",                 "Scala"         );                  for (int i = 0; i < 100000; i++) {             doSort(list);             getRest(list);             getAllCaps(list);             getInitials(list);             getInitialsManually(list);         } Monday, September 30, 13
  • 98.    public static void doSort(List<String> input) {        Collections.sort(input, (a,b)->Integer.compare(a.length(), b.length()));    } Monday, September 30, 13
  • 99. public static void doSort(java.util.List<java.lang.String>); Code: 0: aload_0 1: invokedynamic #36, 0 // InvokeDynamic #4:compare:()Ljava/util/Comparator; 6: invokestatic #37 // Method java/util/Collections.sort ... 9: return Monday, September 30, 13
  • 100. public static void doSort(java.util.List<java.lang.String>); Code: 0: aload_0 1: invokedynamic #36, 0 // InvokeDynamic #4:compare:()Ljava/util/Comparator; 6: invokestatic #37 // Method java/util/Collections.sort ... 9: return InvokeDynamic is used to create the initial lambda object and then cache it forever. Compare to anonymous inner classes, where an instance is created every time. Monday, September 30, 13
  • 101. $ javap -cp dist/RabbitHole.jar -verbose -c com.headius.talks.rabbithole.LambdaStuff Monday, September 30, 13
  • 102. BootstrapMethods: ... 4: #142 invokestatic java/lang/invoke/LambdaMetafactory.metafactory... ...bunch of types here Method arguments: #167 (Ljava/lang/Object;Ljava/lang/Object;)I #168 invokestatic LambdaStuff.lambda$2:(Ljava/lang/String;Ljava/lang/String;)I #169 (Ljava/lang/String;Ljava/lang/String;)I LambdaMetaFactory generates an implementation of our interface (Comparator here) using Method Handles (from JSR292) Monday, September 30, 13
  • 103. BootstrapMethods: ... 4: #142 invokestatic java/lang/invoke/LambdaMetafactory.metafactory... ...bunch of types here Method arguments: #167 (Ljava/lang/Object;Ljava/lang/Object;)I #168 invokestatic LambdaStuff.lambda$2:(Ljava/lang/String;Ljava/lang/String;)I #169 (Ljava/lang/String;Ljava/lang/String;)I LambdaMetaFactory generates an implementation of our interface (Comparator here) using Method Handles (from JSR292) Monday, September 30, 13
  • 104. private static int lambda$2(java.lang.String, java.lang.String); Code: 0: aload_0 1: invokevirtual #53 // Method java/lang/String.length:()I 4: aload_1 5: invokevirtual #53 // Method java/lang/String.length:()I 8: invokestatic #54 // Method java/lang/Integer.compare:(II)I 11: ireturn Lambda body is just a static method; all state is passed to it. Because the wrapper is generated and the body is just a static method, we have no extra classes and potentially no allocation. Monday, September 30, 13
  • 105. Will It Blend? Monday, September 30, 13
  • 106. The Problem • In order to inline code, we need: • A consistent target method • A unique path through the code • Collections.sort’s lambda callback • Will see many different methods • Will be called via many different paths Monday, September 30, 13
  • 107. Caller 1 Caller 2 Caller 3 Caller 4 sort Lambda 1 Lambda 2 Lambda 3 Lambda 4 Too many paths! JVM can’t cope! Monday, September 30, 13
  • 108.     public static String getInitials(List<String> input) {         return input.stream()                 .map(x->x.substring(0,1))                 .collect(Collectors.joining());     }          public static String getInitialsManually(List<String> input) {         StringBuilder builder = new StringBuilder();         UnaryOperator<String> initial = (String x)->x.substring(0,1);         for (String s : input) {             builder.append(initial.apply(s));         }         return builder.toString();     } Monday, September 30, 13
  • 109.    public static void time(Object name, int iterations, Runnable body) {        long start = System.currentTimeMillis();        for (int i = 0; i < iterations; i++) {            body.run();        }        System.out.println(name.toString() + ": " + (System.currentTimeMillis() - start));    } Monday, September 30, 13
  • 110.         Function<List<String>, String> getInitials = LambdaStuff::getInitials;         Function<List<String>, String> getInitialsManually = LambdaStuff::getInitialsManually;                  for (int i = 0; i < 10; i++) {             time("getInitials", 1000000, ()->getInitials.apply(list));             time("getInitialsManually", 1000000, ()->getInitialsManually.apply(list));         } Monday, September 30, 13
  • 111. Drum roll, please... Monday, September 30, 13
  • 112.     public static String getInitials(List<String> input) {         return input.stream()                 .map(x->x.substring(0,1))                 .collect(Collectors.joining());     } mov %r10d,0x24(%r9) ;*putfield nextStage ; - java.util.stream.AbstractPipeline::<init>@28 (line 200) ; - java.util.stream.ReferencePipeline::<init>@3 (line 94) ; - java.util.stream.ReferencePipeline$StatelessOp::<init>@3 (line 627) ; - java.util.stream.ReferencePipeline$3::<init>@16 (line 188) ; - java.util.stream.ReferencePipeline::map@22 (line 187) ; - com.headius.talks.rabbithole.LambdaStuff::getInitials@11 (line 57) Methods like map() and collect() inline... Monday, September 30, 13
  • 113.     public static String getInitials(List<String> input) {         return input.stream()                 .map(x->x.substring(0,1))                 .collect(Collectors.joining());     } callq 0x0000000105973f20 ; OopMap{rbp=Oop [0]=NarrowOop off=2776} ;*invokeinterface apply ; - java.util.stream.ReferencePipeline::collect@118 (line 512) ; {runtime_call} But they can’t inline all those lambdas. Monday, September 30, 13
  • 114. mov 0x60(%r15),%rcx mov %rcx,%r10 add $0x18,%r10 cmp 0x70(%r15),%r10 jae 0x0000000104548d78 mov %r10,0x60(%r15) prefetchnta 0xc0(%r10) mov $0xdf3802e6,%r10d ; {metadata('java/lang/String')} mov 0xa8(%r12,%r10,8),%r10 mov %r10,(%rcx) movl $0xdf3802e6,0x8(%rcx) ; {metadata('java/lang/String')} mov %r12d,0xc(%rcx) mov %r12,0x10(%rcx) ;*new ; - String::substring@65 (line 1961) ; - LambdaStuff::lambda$6@3 (line 75) ; - LambdaStuff$$Lambda$9::apply@4 ; - LambdaStuff::getInitialsManually@45 (line 77)     public static String getInitialsManually(List<String> input) {         StringBuilder builder = new StringBuilder();         UnaryOperator<String> initial = (String x)->x.substring(0,1);         for (String s : input) {             builder.append(initial.apply(s));         }         return builder.toString();     } Monday, September 30, 13
  • 115. mov 0x60(%r15),%rcx mov %rcx,%r10 add $0x18,%r10 cmp 0x70(%r15),%r10 jae 0x0000000104548d78 mov %r10,0x60(%r15) prefetchnta 0xc0(%r10) mov $0xdf3802e6,%r10d ; {metadata('java/lang/String')} mov 0xa8(%r12,%r10,8),%r10 mov %r10,(%rcx) movl $0xdf3802e6,0x8(%rcx) ; {metadata('java/lang/String')} mov %r12d,0xc(%rcx) mov %r12,0x10(%rcx) ;*new ; - String::substring@65 (line 1961) ; - LambdaStuff::lambda$6@3 (line 75) ; - LambdaStuff$$Lambda$9::apply@4 ; - LambdaStuff::getInitialsManually@45 (line 77)     public static String getInitialsManually(List<String> input) {         StringBuilder builder = new StringBuilder();         UnaryOperator<String> initial = (String x)->x.substring(0,1);         for (String s : input) {             builder.append(initial.apply(s));         }         return builder.toString();     } Monday, September 30, 13
  • 117. The JVM is not perfect. Monday, September 30, 13
  • 118. Every feature has a cost. Monday, September 30, 13
  • 119. You’ll be a better developer if you remember those facts... Monday, September 30, 13
  • 120. ...and you aren’t afraid to go down the rabbit hole. Monday, September 30, 13
  • 121. ThankYou! • Charles Oliver Nutter • @headius • headius@headius.com • http://blog.headius.com Monday, September 30, 13
  • 123. #5: Escape Analysis Monday, September 30, 13
  • 124. Vocabulary • Escape analysis • Determining that the data enclosed inside an object is the only part of the object needed, so the object does not need to be allocated Monday, September 30, 13
  • 125. Escape Analysis Object created Object goes out of scope Object used only in this method Field data put into locals No object to dereference Object data used from fields Monday, September 30, 13
  • 126. Breaking EA • Object assigned to a non-EA object’s field • Object may go to a method not inlined • Object may go to a branch not yet followed • or potentially, crosses any branch at all Monday, September 30, 13