SlideShare uma empresa Scribd logo
1 de 132
Baixar para ler offline
Fast as C
How to write really terrible Java
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
Benchmarks!
• Lots of benchmarks out there, but…
• Most of them already terrible Java
• Usually very synthetic cases
• Not particularly illustrative
for ( int i=idxMin; i<idxMax; ++i ) {
// count flips
if ( p0 != 0 ) {
int pp0 = p0, pp1 = p1, pp2 = p2, pp3 = p3, pp4 = p4, pp5 = p5,
pp6 = p6, pp7 = p7, pp8 = p8, pp9 = p9, pp10 = p10, pp11 = p11;
int flips = 1;
for ( ;; ++flips ) {
int t = pp0;
switch ( t ) {
case 1: pp0 = pp1; pp1 = t; break;
case 2: pp0 = pp2; pp2 = t; break;
case 3: pp0 = pp3; pp3 = t;
t = pp2; pp2 = pp1; pp1 = t;
break;
case 4: pp0 = pp4; pp4 = t;
t = pp3; pp3 = pp1; pp1 = t;
break;
case 5: pp0 = pp5; pp5 = t;
t = pp4; pp4 = pp1; pp1 = t;
t = pp3; pp3 = pp2; pp2 = t;
break;
What are we going to
do today?
• Look at some Java features and patterns
• See how they’re compiled to bytecode
• Watch what the JVM does with them
• Examine the actual native code they become
WHY?!
Who AreYou?
• Java developers?
• Performance engineers?
• Debuggers?
• All of the above?
Mechanical Sympathy
• Features with hidden costs
• Anonymous inner classes
• Structural types in Scala
• Serialization
• Code design impacts performance
• JVM can’t do everything for you
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
Sufficiently Smart
Compiler
If you wait long enough*, the JVM will eventually
optimize everything perfectly and even bad
code will perform well.
* for some definition of “long”
Pre-dive Prep
• Profiling with various tools
• YourKit, Flight Recorder, JMH
• Algorithmic complexity
• Allocation/GC overhead
• Latency/blocking in IO and system calls
Part One:The Primer
Vocabulary
• Source
• The .java text that represents a program
• Bytecode
• The binary version of the program that
all JVMs can load and execute
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
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
JVM 101
Java source JVM bytecode
javac
JVM bytecode
Bytecode
interpreter
runs inside gather
information
JIT
compiler
triggers
Native code
produces
executes
backs off
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
Inlining Instance
Method
Load target and
arguments
Target type is same as inlined?
Method
lookup
Run target
code directly
Yes
No
Run target
method as a call
Inlining Static or Special
Method
Load arguments
Run target
code directly
Our Tools
• javac, obviously
• javap to dump .class data
• -XX:+PrintCompilation and

-XX:+PrintInlining
• -XX:+PrintAssembly
• -XX:+LogCompilation and JITWatch
Hello, world!
• We’ll start with something simple.
package com.headius.talks.geekout;
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}
Level 1: Bytecode
• javap
• Java class file disassembler
• Dump structure, data, metadata, and code
$ javap -cp dist/GeekOut.jar 
com.headius.talks.geekout.HelloWorld
Compiled from "HelloWorld.java"
public class com.headius.talks.geekout.HelloWorld {
public com.headius.talks.geekout.HelloWorld();
public static void main(java.lang.String[]);
}
$ javap -cp dist/GeekOut.jar 
-c 
com.headius.talks.geekout.HelloWorld
Compiled from "HelloWorld.java"
public class com.headius.talks.geekout.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
}
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
$ javap -cp dist/GeekOut.jar 
-c 
com.headius.talks.geekout.HelloWorld
Compiled from "HelloWorld.java"
public class com.headius.talks.geekout.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
}
Level 2: Compiler Logs
• -XX:+PrintCompilation
• Display methods as they compile
• -XX:+PrintInlining
• Display inlined methods as nested
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”
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!");
    }
}
$ java -Xbatch
-XX:-TieredCompilation 
-XX:+PrintCompilation 
-cp dist/GeekOut.jar 
com.headius.talks.geekout.HelloWorld 
2> /dev/null
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.geekout.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.geekout.HelloWorld::main @ 2 (18 bytes)
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.geekout.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.geekout.HelloWorld::main @ 2 (18 bytes)
$ java -Xbatch 
-XX:-TieredCompilation 
-XX:+PrintCompilation 
-XX:+UnlockDiagnosticVMOptions 
-XX:+PrintInlining 
-cp dist/Geekout.jar 
com.headius.talks.geekout.HelloWorld
2> /dev/null
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.geekout.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.geekout.HelloWorld::main @ 2 (18 bytes)
@ 8 com.headius.talks.geekout.HelloWorld::hello (9 bytes)
already compiled into a big method
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.geekout.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.geekout.HelloWorld::main @ 2 (18 bytes)
@ 8 com.headius.talks.geekout.HelloWorld::hello (9 bytes)
already compiled into a big method
Level 3: Native Code
• -XX:+PrintAssembly
• Dumps “human readable” JITed code
• Google for “hotspot printassembly”
• Aren’t you excited?!
$ java -Xbatch 
-XX:-TieredCompilation 
-XX:+UnlockDiagnosticVMOptions 
-XX:+PrintAssembly 
-cp dist/GeekOut.jar 
com.headius.talks.geekout.HelloWorld
2> /dev/null
| less
Decoding compiled method 0x0000000110526110:
Code:
[Entry Point]
[Verified Entry Point]
[Constants]
# {method}
{0x00000001100a6420} 'hello' '()V' in 'com/headius/talks/geekout/HelloWorld'
# [sp+0x70] (sp of caller)
0x0000000110526300: mov %eax,-0x14000(%rsp)
0x0000000110526307: push %rbp
0x0000000110526308: sub $0x60,%rsp ;*synchronization entry
; - com.headius.talks.geekout.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.geekout.HelloWorld::hello@0 (line 13)
0x000000011052631a: mov %r11d,0x10(%rsp)
0x000000011052631f: test %r11d,%r11d
0x0000000110526322: je 0x000000011052664e ;*invokevirtual println
; - com.headius.talks.geekout.HelloWorld::hello@5 (line 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
public class Tiny1 {
    public static void main(String[] args) {
        for (int i = 0; i < 100000; i++) {
            tiny();
        }
    }
    
    public static int tiny() {
        return 1 + 1;
    }
}
public static int tiny();
Code:
0: iconst_2
1: ireturn
iconst_2: load integer 2 on stack
ireturn: return int
110 3 b com.headius.talks.geekout.Tiny1::tiny (2 bytes)
111 4 % b com.headius.talks.geekout.Tiny1::main @ 2 (19 bytes)
@ 8 com.headius.talks.geekout.Tiny1::tiny
(2 bytes) inline (hot)
{0x000000010994c3c0} 'tiny' '()I' in 'com/headius/talks/geekout/Tiny1'
# [sp+0x40] (sp of caller)
0x0000000109e566a0: mov %eax,-0x14000(%rsp)
0x0000000109e566a7: push %rbp
0x0000000109e566a8: sub $0x30,%rsp ;*iconst_2
; -
com.headius.talks.geekout.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
{0x000000010994c3c0} 'tiny' '()I' in 'com/headius/talks/geekout/Tiny1'
# [sp+0x40] (sp of caller)
0x0000000109e566a0: mov %eax,-0x14000(%rsp)
0x0000000109e566a7: push %rbp
0x0000000109e566a8: sub $0x30,%rsp ;*iconst_2
; -
com.headius.talks.geekout.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
{0x000000010e67d300} 'main' '([Ljava/lang/String;)V' in 'com/headius/talks/geekout/Tiny1'
0x000000010eb879a0: mov %eax,-0x14000(%rsp)
0x000000010eb879a7: push %rbp
0x000000010eb879a8: sub $0x40,%rsp ;*iconst_0
; - com.headius.talks.geekout.Tiny1::main@0 (line 5)
0x000000010eb879ac: mov $0x0,%esi
0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1
; - com.headius.talks.geekout.Tiny1::main@2 (line 5)
0x000000010eb879b6: xchg %ax,%ax
0x000000010eb879b8: inc %esi ; OopMap{off=26}
;*goto
; - com.headius.talks.geekout.Tiny1::main@15 (line 5)
0x000000010eb879ba: test %eax,-0x9a08c0(%rip) # 0x000000010e1e7100
;*goto
; - com.headius.talks.geekout.Tiny1::main@15 (line 5)
; {poll}
0x000000010eb879c0: cmp $0x186a0,%esi
0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge
; - com.headius.talks.geekout.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.geekout.Tiny1::main@18 (line 8)
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
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
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
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
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
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
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
1: mov $0,%esi
2: jmpq 4:
3: inc %esi
4: cmp $1000000,%esi
5: jl 3:
6: retq
1: retq
-XX:+LogCompilation
• Combines PrintCompilation and
PrintInlining in one horrendous XML file
• OpenJDK tool “LogCompilation” for CLI
• OpenJDK tool “JITWatch” for GUI
scopes_pcs_offset='1384' dependencies_offset='1576' handler_table_offset='1592' nul_chk_table_offset='1736'
oops_offset='992' method='org/jruby/lexer/yacc/ByteArrayLexerSource$ByteArrayCursor read ()I' bytes='49'
count='5296' backedge_count='1' iicount='10296' stamp='0.412'/>
<writer thread='4425007104'/>
<nmethod compile_id='21' compiler='C2' entry='4345862528' size='1152' address='4345862160'
relocation_offset='288' insts_offset='368' stub_offset='688' scopes_data_offset='840' scopes_pcs_offset='904'
dependencies_offset='1016' handler_table_offset='1032' oops_offset='784' method='org/jruby/lexer/yacc/
ByteArrayLexerSource forward (I)I' bytes='111' count='5296' backedge_count='1' iicount='10296' stamp='0.412'/>
<writer thread='4300214272'/>
<task_queued compile_id='22' method='org/jruby/lexer/yacc/ByteArrayLexerSource read ()I' bytes='10'
count='5000' backedge_count='1' iicount='10000' stamp='0.433' comment='count' hot_count='10000'/>
<writer thread='4426067968'/>
<nmethod compile_id='22' compiler='C2' entry='4345885984' size='1888' address='4345885584'
relocation_offset='288' insts_offset='400' stub_offset='912' scopes_data_offset='1104'
scopes_pcs_offset='1496' dependencies_offset='1704' handler_table_offset='1720' nul_chk_table_offset='1864'
oops_offset='1024' method='org/jruby/lexer/yacc/ByteArrayLexerSource read ()I' bytes='10' count='5044'
backedge_count='1' iicount='10044' stamp='0.435'/>
<writer thread='4300214272'/>
<task_queued compile_id='23' method='java/util/HashMap hash (I)I' bytes='23' count='5000' backedge_count='1'
iicount='10000' stamp='0.442' comment='count' hot_count='10000'/>
<writer thread='4425007104'/>
<nmethod compile_id='23' compiler='C2' entry='4345887808' size='440' address='4345887504'
relocation_offset='288' insts_offset='304' stub_offset='368' scopes_data_offset='392' scopes_pcs_offset='400'
dependencies_offset='432' method='java/util/HashMap hash (I)I' bytes='23' count='5039' backedge_count='1'
iicount='10039' stamp='0.442'/>
<writer thread='4300214272'/>
<dependency_failed type='abstract_with_unique_concrete_subtype' ctxk='org/jruby/lexer/yacc/LexerSource'
x='org/jruby/lexer/yacc/ByteArrayLexerSource' witness='org/jruby/lexer/yacc/InputStreamLexerSource'
stamp='0.456'/>
<dependency_failed type='abstract_with_unique_concrete_subtype' ctxk='org/jruby/lexer/yacc/LexerSource'
x='org/jruby/lexer/yacc/ByteArrayLexerSource' witness='org/jruby/lexer/yacc/InputStreamLexerSource'
stamp='0.456'/>
<dependency_failed type='abstract_with_unique_concrete_subtype' ctxk='org/jruby/lexer/yacc/LexerSource'
x='org/jruby/lexer/yacc/ByteArrayLexerSource' witness='org/jruby/lexer/yacc/InputStreamLexerSource'
stamp='0.456'/>
<dependency_failed type='abstract_with_unique_concrete_subtype' ctxk='org/jruby/lexer/yacc/LexerSource'
x='org/jruby/lexer/yacc/ByteArrayLexerSource' witness='org/jruby/lexer/yacc/InputStreamLexerSource'
stamp='0.456'/>
$ java -jar logc.jar hotspot.log
1 java.lang.String::hashCode (67 bytes)
2 Accumulator::addSqrt (7 bytes)
3 Accumulator::sqrt (6 bytes)
logc with no flags = PrintCompilation
$ java -jar logc.jar -i hotspot.log
1 java.lang.String::hashCode (67 bytes)
2 Accumulator::addSqrt (7 bytes)
@ 2 Accumulator::sqrt (6 bytes) (end time: 0.0660 nodes: 36)
@ 2 java.lang.Math::sqrt (5 bytes)
3 Accumulator::sqrt (6 bytes)
@ 2 java.lang.Math::sqrt (5 bytes)
-i flag = PrintCompilation + PrintInlining
It’s not that hard
once you know what to
look at.
Part 2:The Fun Stuff
Java Features
• final fields
• synchronized and volatile
• string switch
• lambda
• single-implementer interfaces
• transient objects
#1: Final Fields
• Final fields can’t be modified
• The pipeline can take advantage
• ...but it doesn’t always
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);
}
}
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");
    private static int addHashes() {
        return MY_STRING.hashCode() + MY_PROPERTY.hashCode();
    }
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)
    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();
    }    
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
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)
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)
ACHIEVEMENT UNLOCKED:
Find something Hotspot could do better
#2: Concurrency Stuff
• What does “synchronized” do?
• What does “volatile” do?
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();
    }
}
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
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
'getTime' '()J' in 'com/headius/talks/geekout/Concurrency'
movabs $0x1015dbd3e,%r10
callq *%r10 ;*invokestatic currentTimeMillis
; - Concurrency::getTime@0 (line 22)
retq
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)
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)
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)
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
Volatile
• Forces memory visibility, access ordering
• Prevents some optimizations
• Similar impact to unnecessary locking
• ...but it can’t ever be removed
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?
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?
public static Object getVariable(RubyBasicObject object, int index) {
Object[] ivarTable;
if (index < 0 || (ivarTable = object.varTable) == null) return null;
if (ivarTable.length > index) return ivarTable[index];
return null;
}
Yuck!
#3: String Switch
• Added in Java 7
• ...and there was much rejoicing
• But how does it really work?
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
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;
        }
...
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
Direct branch
switch (args.length) {
    case 2000000: count = "two million"; break;
    case 1000000: count = "one million"; break;
    case 3000000: count = "three million"; break;
}
49: lookupswitch { // 3
1000000: 90
2000000: 84
3000000: 96
default: 99
}
Binary search
Comparison
• tableswitch is O(1)
• Indexed lookup of target
• lookupswitch is O(log n)
• Binary search for target
String Switch
• What kind of switch do we use for String?
• Table doesn’t work for hashcodes
• Lookup might collide
• Answer: both, plus .equals()
    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?";
        }
    }
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...
Hash and jump target for “Scala”
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
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!
Scala’s index and target
   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?";
       }
   }
It’s just a hash table!
#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
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);
        }
   public static void doSort(List<String> input) {
       Collections.sort(input,
(a,b)->Integer.compare(a.length(), b.length()));
   }
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
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.
$ javap -cp dist/GeekOut.jar 
-verbose 
-c 
com.headius.talks.geekout.LambdaStuff
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)
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 class files
and potentially no allocation.
Will It Blend?
    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();
    }
   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));
   }
        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));
        }
Drum roll, please...
    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.geekout.LambdaStuff::getInitials@11 (line 57)
Methods like map() and collect() inline...
    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.
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
Caller 1
Caller 2
Caller 3
Caller 4
sort
Lambda 1
Lambda 2
Lambda 3
Lambda 4
Too many paths!
JVM can’t cope!
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();
    }
Yuck!
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();
    }
Yuck!
Yay!
#5 Single-impl Interface
• Interfaces are everywhere
• Frequently using a common base class
• Frequently single implementor of a method
IRubyObject
getMetaClass()
RubyBasicObject
final getMetaClass()
RubyObject
RubyArray RubyString RubyHash
@Override
public final RubyClass getMetaClass() {
return metaClass;
}
public static boolean testType(RubyClass original, IRubyObject self) {

return self.getMetaClass() == original;

}
450 Bootstrap::testType (16 bytes)
@ 1 IRubyObject::getMetaClass (0 bytes) (end time: 0.0000)
type profile IRubyObject -> RubyArray (41%)
JVM sees only target type,
even though there’s one impl of method
Single-implementer
interfaces look like
many implementers!
public static boolean testType(RubyClass original, IRubyObject self) {
return ((RubyBasicObject)self).getMetaClass() == original;
}
Yuck!
Lessons
The JVM is not perfect.
Every feature has a cost.
You’ll be a better
developer if you
remember those facts...
...and you aren’t afraid
to look under the covers.
ThankYou!
• Charles Oliver Nutter
• @headius
• headius@headius.com
• http://blog.headius.com

Mais conteúdo relacionado

Mais procurados

Java 8 Stream API. A different way to process collections.
Java 8 Stream API. A different way to process collections.Java 8 Stream API. A different way to process collections.
Java 8 Stream API. A different way to process collections.David Gómez García
 
Introducing Drools
Introducing DroolsIntroducing Drools
Introducing DroolsMario Fusco
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with SpringJoshua Long
 
Action Jackson! Effective JSON processing in Spring Boot Applications
Action Jackson! Effective JSON processing in Spring Boot ApplicationsAction Jackson! Effective JSON processing in Spring Boot Applications
Action Jackson! Effective JSON processing in Spring Boot ApplicationsJoris Kuipers
 
Java 9/10/11 - What's new and why you should upgrade
Java 9/10/11 - What's new and why you should upgradeJava 9/10/11 - What's new and why you should upgrade
Java 9/10/11 - What's new and why you should upgradeSimone Bordet
 
Web Components and Security
Web Components and SecurityWeb Components and Security
Web Components and SecurityTyler Peterson
 
Celery의 빛과 그림자
Celery의 빛과 그림자Celery의 빛과 그림자
Celery의 빛과 그림자Minyoung Jeong
 
Introduction to ReactJS
Introduction to ReactJSIntroduction to ReactJS
Introduction to ReactJSHoang Long
 
Software Craftsmanship @Code Camp Festival 2022.pdf
Software Craftsmanship @Code Camp Festival 2022.pdfSoftware Craftsmanship @Code Camp Festival 2022.pdf
Software Craftsmanship @Code Camp Festival 2022.pdfVictor Rentea
 
Mocking in Java with Mockito
Mocking in Java with MockitoMocking in Java with Mockito
Mocking in Java with MockitoRichard Paul
 
Memory Management: What You Need to Know When Moving to Java 8
Memory Management: What You Need to Know When Moving to Java 8Memory Management: What You Need to Know When Moving to Java 8
Memory Management: What You Need to Know When Moving to Java 8AppDynamics
 
The tests are trying to tell you something@VoxxedBucharest.pptx
The tests are trying to tell you something@VoxxedBucharest.pptxThe tests are trying to tell you something@VoxxedBucharest.pptx
The tests are trying to tell you something@VoxxedBucharest.pptxVictor Rentea
 
Clean Code @Voxxed Days Cluj 2023 - opening Keynote
Clean Code @Voxxed Days Cluj 2023 - opening KeynoteClean Code @Voxxed Days Cluj 2023 - opening Keynote
Clean Code @Voxxed Days Cluj 2023 - opening KeynoteVictor Rentea
 
ES2015 / ES6: Basics of modern Javascript
ES2015 / ES6: Basics of modern JavascriptES2015 / ES6: Basics of modern Javascript
ES2015 / ES6: Basics of modern JavascriptWojciech Dzikowski
 
Basic Concept of Node.js & NPM
Basic Concept of Node.js & NPMBasic Concept of Node.js & NPM
Basic Concept of Node.js & NPMBhargav Anadkat
 

Mais procurados (20)

Java 8 Stream API. A different way to process collections.
Java 8 Stream API. A different way to process collections.Java 8 Stream API. A different way to process collections.
Java 8 Stream API. A different way to process collections.
 
Drools rule Concepts
Drools rule ConceptsDrools rule Concepts
Drools rule Concepts
 
Introducing Drools
Introducing DroolsIntroducing Drools
Introducing Drools
 
Clean code
Clean codeClean code
Clean code
 
Spring data jpa
Spring data jpaSpring data jpa
Spring data jpa
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with Spring
 
Action Jackson! Effective JSON processing in Spring Boot Applications
Action Jackson! Effective JSON processing in Spring Boot ApplicationsAction Jackson! Effective JSON processing in Spring Boot Applications
Action Jackson! Effective JSON processing in Spring Boot Applications
 
Java 9/10/11 - What's new and why you should upgrade
Java 9/10/11 - What's new and why you should upgradeJava 9/10/11 - What's new and why you should upgrade
Java 9/10/11 - What's new and why you should upgrade
 
Clean Code
Clean CodeClean Code
Clean Code
 
Web Components and Security
Web Components and SecurityWeb Components and Security
Web Components and Security
 
Celery의 빛과 그림자
Celery의 빛과 그림자Celery의 빛과 그림자
Celery의 빛과 그림자
 
Introduction to ReactJS
Introduction to ReactJSIntroduction to ReactJS
Introduction to ReactJS
 
Software Craftsmanship @Code Camp Festival 2022.pdf
Software Craftsmanship @Code Camp Festival 2022.pdfSoftware Craftsmanship @Code Camp Festival 2022.pdf
Software Craftsmanship @Code Camp Festival 2022.pdf
 
Mocking in Java with Mockito
Mocking in Java with MockitoMocking in Java with Mockito
Mocking in Java with Mockito
 
Memory Management: What You Need to Know When Moving to Java 8
Memory Management: What You Need to Know When Moving to Java 8Memory Management: What You Need to Know When Moving to Java 8
Memory Management: What You Need to Know When Moving to Java 8
 
The tests are trying to tell you something@VoxxedBucharest.pptx
The tests are trying to tell you something@VoxxedBucharest.pptxThe tests are trying to tell you something@VoxxedBucharest.pptx
The tests are trying to tell you something@VoxxedBucharest.pptx
 
Clean Code @Voxxed Days Cluj 2023 - opening Keynote
Clean Code @Voxxed Days Cluj 2023 - opening KeynoteClean Code @Voxxed Days Cluj 2023 - opening Keynote
Clean Code @Voxxed Days Cluj 2023 - opening Keynote
 
ES2015 / ES6: Basics of modern Javascript
ES2015 / ES6: Basics of modern JavascriptES2015 / ES6: Basics of modern Javascript
ES2015 / ES6: Basics of modern Javascript
 
Basic Concept of Node.js & NPM
Basic Concept of Node.js & NPMBasic Concept of Node.js & NPM
Basic Concept of Node.js & NPM
 
Java 11 to 17 : What's new !?
Java 11 to 17 : What's new !?Java 11 to 17 : What's new !?
Java 11 to 17 : What's new !?
 

Destaque

Down the Rabbit Hole: An Adventure in JVM Wonderland
Down the Rabbit Hole: An Adventure in JVM WonderlandDown the Rabbit Hole: An Adventure in JVM Wonderland
Down the Rabbit Hole: An Adventure in JVM WonderlandCharles Nutter
 
Зависимые типы в GHC 8. Максим Талдыкин
Зависимые типы в GHC 8. Максим ТалдыкинЗависимые типы в GHC 8. Максим Талдыкин
Зависимые типы в GHC 8. Максим ТалдыкинЮрий Сыровецкий
 
JVM for Dummies - OSCON 2011
JVM for Dummies - OSCON 2011JVM for Dummies - OSCON 2011
JVM for Dummies - OSCON 2011Charles Nutter
 
Ruby Performance - The Last Mile - RubyConf India 2016
Ruby Performance - The Last Mile - RubyConf India 2016Ruby Performance - The Last Mile - RubyConf India 2016
Ruby Performance - The Last Mile - RubyConf India 2016Charles 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
 
JavaOne 2011 - JVM Bytecode for Dummies
JavaOne 2011 - JVM Bytecode for DummiesJavaOne 2011 - JVM Bytecode for Dummies
JavaOne 2011 - JVM Bytecode for DummiesCharles Nutter
 
Open Source Software Needs You!
Open Source Software Needs You!Open Source Software Needs You!
Open Source Software Needs You!Charles Nutter
 
JavaOne 2012 - JVM JIT for Dummies
JavaOne 2012 - JVM JIT for DummiesJavaOne 2012 - JVM JIT for Dummies
JavaOne 2012 - JVM JIT for DummiesCharles Nutter
 
SREcon 2016 Performance Checklists for SREs
SREcon 2016 Performance Checklists for SREsSREcon 2016 Performance Checklists for SREs
SREcon 2016 Performance Checklists for SREsBrendan Gregg
 

Destaque (9)

Down the Rabbit Hole: An Adventure in JVM Wonderland
Down the Rabbit Hole: An Adventure in JVM WonderlandDown the Rabbit Hole: An Adventure in JVM Wonderland
Down the Rabbit Hole: An Adventure in JVM Wonderland
 
Зависимые типы в GHC 8. Максим Талдыкин
Зависимые типы в GHC 8. Максим ТалдыкинЗависимые типы в GHC 8. Максим Талдыкин
Зависимые типы в GHC 8. Максим Талдыкин
 
JVM for Dummies - OSCON 2011
JVM for Dummies - OSCON 2011JVM for Dummies - OSCON 2011
JVM for Dummies - OSCON 2011
 
Ruby Performance - The Last Mile - RubyConf India 2016
Ruby Performance - The Last Mile - RubyConf India 2016Ruby Performance - The Last Mile - RubyConf India 2016
Ruby Performance - The Last Mile - RubyConf India 2016
 
InvokeBinder: Fluent Programming for Method Handles
InvokeBinder: Fluent Programming for Method HandlesInvokeBinder: Fluent Programming for Method Handles
InvokeBinder: Fluent Programming for Method Handles
 
JavaOne 2011 - JVM Bytecode for Dummies
JavaOne 2011 - JVM Bytecode for DummiesJavaOne 2011 - JVM Bytecode for Dummies
JavaOne 2011 - JVM Bytecode for Dummies
 
Open Source Software Needs You!
Open Source Software Needs You!Open Source Software Needs You!
Open Source Software Needs You!
 
JavaOne 2012 - JVM JIT for Dummies
JavaOne 2012 - JVM JIT for DummiesJavaOne 2012 - JVM JIT for Dummies
JavaOne 2012 - JVM JIT for Dummies
 
SREcon 2016 Performance Checklists for SREs
SREcon 2016 Performance Checklists for SREsSREcon 2016 Performance Checklists for SREs
SREcon 2016 Performance Checklists for SREs
 

Semelhante a Fast as C: How to Write Really Terrible Java

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
 
Tips and tricks for building high performance android apps using native code
Tips and tricks for building high performance android apps using native codeTips and tricks for building high performance android apps using native code
Tips and tricks for building high performance android apps using native codeKenneth Geisshirt
 
Mastering Java Bytecode - JAX.de 2012
Mastering Java Bytecode - JAX.de 2012Mastering Java Bytecode - JAX.de 2012
Mastering Java Bytecode - JAX.de 2012Anton Arhipov
 
Nodejs - Should Ruby Developers Care?
Nodejs - Should Ruby Developers Care?Nodejs - Should Ruby Developers Care?
Nodejs - Should Ruby Developers Care?Felix Geisendörfer
 
Java Bytecode for Discriminating Developers - JavaZone 2011
Java Bytecode for Discriminating Developers - JavaZone 2011Java Bytecode for Discriminating Developers - JavaZone 2011
Java Bytecode for Discriminating Developers - JavaZone 2011Anton Arhipov
 
Java 7 Whats New(), Whats Next() from Oredev
Java 7 Whats New(), Whats Next() from OredevJava 7 Whats New(), Whats Next() from Oredev
Java 7 Whats New(), Whats Next() from OredevMattias Karlsson
 
How to reverse engineer Android applications
How to reverse engineer Android applicationsHow to reverse engineer Android applications
How to reverse engineer Android applicationshubx
 
How to reverse engineer Android applications—using a popular word game as an ...
How to reverse engineer Android applications—using a popular word game as an ...How to reverse engineer Android applications—using a popular word game as an ...
How to reverse engineer Android applications—using a popular word game as an ...Christoph Matthies
 
Ahead-Of-Time Compilation of Java Applications
Ahead-Of-Time Compilation of Java ApplicationsAhead-Of-Time Compilation of Java Applications
Ahead-Of-Time Compilation of Java ApplicationsNikita Lipsky
 
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...Charles Nutter
 
Java Bytecode For Discriminating Developers - GeeCON 2011
Java Bytecode For Discriminating Developers - GeeCON 2011Java Bytecode For Discriminating Developers - GeeCON 2011
Java Bytecode For Discriminating Developers - GeeCON 2011Anton Arhipov
 
The State of Managed Runtimes 2013, by Attila Szegedi
The State of Managed Runtimes 2013, by Attila SzegediThe State of Managed Runtimes 2013, by Attila Szegedi
The State of Managed Runtimes 2013, by Attila SzegediZeroTurnaround
 
GOTO Night with Charles Nutter Slides
GOTO Night with Charles Nutter SlidesGOTO Night with Charles Nutter Slides
GOTO Night with Charles Nutter SlidesAlexandra Masterson
 
2013 syscan360 yuki_chen_syscan360_exploit your java native vulnerabilities o...
2013 syscan360 yuki_chen_syscan360_exploit your java native vulnerabilities o...2013 syscan360 yuki_chen_syscan360_exploit your java native vulnerabilities o...
2013 syscan360 yuki_chen_syscan360_exploit your java native vulnerabilities o...chen yuki
 
Search for Vulnerabilities Using Static Code Analysis
Search for Vulnerabilities Using Static Code AnalysisSearch for Vulnerabilities Using Static Code Analysis
Search for Vulnerabilities Using Static Code AnalysisAndrey Karpov
 

Semelhante a Fast as C: How to Write Really Terrible Java (20)

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++
 
Tips and tricks for building high performance android apps using native code
Tips and tricks for building high performance android apps using native codeTips and tricks for building high performance android apps using native code
Tips and tricks for building high performance android apps using native code
 
Mastering Java Bytecode - JAX.de 2012
Mastering Java Bytecode - JAX.de 2012Mastering Java Bytecode - JAX.de 2012
Mastering Java Bytecode - JAX.de 2012
 
Java for the Beginners
Java for the BeginnersJava for the Beginners
Java for the Beginners
 
HotSpotコトハジメ
HotSpotコトハジメHotSpotコトハジメ
HotSpotコトハジメ
 
Nodejs - Should Ruby Developers Care?
Nodejs - Should Ruby Developers Care?Nodejs - Should Ruby Developers Care?
Nodejs - Should Ruby Developers Care?
 
Down the Rabbit Hole
Down the Rabbit HoleDown the Rabbit Hole
Down the Rabbit Hole
 
Java Bytecode for Discriminating Developers - JavaZone 2011
Java Bytecode for Discriminating Developers - JavaZone 2011Java Bytecode for Discriminating Developers - JavaZone 2011
Java Bytecode for Discriminating Developers - JavaZone 2011
 
Java 7 Whats New(), Whats Next() from Oredev
Java 7 Whats New(), Whats Next() from OredevJava 7 Whats New(), Whats Next() from Oredev
Java 7 Whats New(), Whats Next() from Oredev
 
Nodejs - A quick tour (v6)
Nodejs - A quick tour (v6)Nodejs - A quick tour (v6)
Nodejs - A quick tour (v6)
 
How to reverse engineer Android applications
How to reverse engineer Android applicationsHow to reverse engineer Android applications
How to reverse engineer Android applications
 
How to reverse engineer Android applications—using a popular word game as an ...
How to reverse engineer Android applications—using a popular word game as an ...How to reverse engineer Android applications—using a popular word game as an ...
How to reverse engineer Android applications—using a popular word game as an ...
 
Ahead-Of-Time Compilation of Java Applications
Ahead-Of-Time Compilation of Java ApplicationsAhead-Of-Time Compilation of Java Applications
Ahead-Of-Time Compilation of Java Applications
 
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
 
Java Bytecode For Discriminating Developers - GeeCON 2011
Java Bytecode For Discriminating Developers - GeeCON 2011Java Bytecode For Discriminating Developers - GeeCON 2011
Java Bytecode For Discriminating Developers - GeeCON 2011
 
In Vogue Dynamic
In Vogue DynamicIn Vogue Dynamic
In Vogue Dynamic
 
The State of Managed Runtimes 2013, by Attila Szegedi
The State of Managed Runtimes 2013, by Attila SzegediThe State of Managed Runtimes 2013, by Attila Szegedi
The State of Managed Runtimes 2013, by Attila Szegedi
 
GOTO Night with Charles Nutter Slides
GOTO Night with Charles Nutter SlidesGOTO Night with Charles Nutter Slides
GOTO Night with Charles Nutter Slides
 
2013 syscan360 yuki_chen_syscan360_exploit your java native vulnerabilities o...
2013 syscan360 yuki_chen_syscan360_exploit your java native vulnerabilities o...2013 syscan360 yuki_chen_syscan360_exploit your java native vulnerabilities o...
2013 syscan360 yuki_chen_syscan360_exploit your java native vulnerabilities o...
 
Search for Vulnerabilities Using Static Code Analysis
Search for Vulnerabilities Using Static Code AnalysisSearch for Vulnerabilities Using Static Code Analysis
Search for Vulnerabilities Using Static Code Analysis
 

Mais de 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
 
JRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVMJRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVMCharles Nutter
 
JRuby and Invokedynamic - Japan JUG 2015
JRuby and Invokedynamic - Japan JUG 2015JRuby and Invokedynamic - Japan JUG 2015
JRuby and Invokedynamic - Japan JUG 2015Charles Nutter
 
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
 
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! Sydney 2013
Beyond JVM - YOW! Sydney 2013Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013Charles 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
 

Mais de 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
 
JRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVMJRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVM
 
JRuby and Invokedynamic - Japan JUG 2015
JRuby and Invokedynamic - Japan JUG 2015JRuby and Invokedynamic - Japan JUG 2015
JRuby and Invokedynamic - Japan JUG 2015
 
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
 
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! Sydney 2013
Beyond JVM - YOW! Sydney 2013Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013
 
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
 

Último

Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfhans926745
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 

Último (20)

Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 

Fast as C: How to Write Really Terrible Java

  • 1. Fast as C How to write really terrible Java
  • 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
  • 3. Benchmarks! • Lots of benchmarks out there, but… • Most of them already terrible Java • Usually very synthetic cases • Not particularly illustrative
  • 4. for ( int i=idxMin; i<idxMax; ++i ) { // count flips if ( p0 != 0 ) { int pp0 = p0, pp1 = p1, pp2 = p2, pp3 = p3, pp4 = p4, pp5 = p5, pp6 = p6, pp7 = p7, pp8 = p8, pp9 = p9, pp10 = p10, pp11 = p11; int flips = 1; for ( ;; ++flips ) { int t = pp0; switch ( t ) { case 1: pp0 = pp1; pp1 = t; break; case 2: pp0 = pp2; pp2 = t; break; case 3: pp0 = pp3; pp3 = t; t = pp2; pp2 = pp1; pp1 = t; break; case 4: pp0 = pp4; pp4 = t; t = pp3; pp3 = pp1; pp1 = t; break; case 5: pp0 = pp5; pp5 = t; t = pp4; pp4 = pp1; pp1 = t; t = pp3; pp3 = pp2; pp2 = t; break;
  • 5. What are we going to do today? • Look at some Java features and patterns • See how they’re compiled to bytecode • Watch what the JVM does with them • Examine the actual native code they become
  • 7. Who AreYou? • Java developers? • Performance engineers? • Debuggers? • All of the above?
  • 8. Mechanical Sympathy • Features with hidden costs • Anonymous inner classes • Structural types in Scala • Serialization • Code design impacts performance • JVM can’t do everything for you
  • 9. 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
  • 10. Sufficiently Smart Compiler If you wait long enough*, the JVM will eventually optimize everything perfectly and even bad code will perform well. * for some definition of “long”
  • 11. Pre-dive Prep • Profiling with various tools • YourKit, Flight Recorder, JMH • Algorithmic complexity • Allocation/GC overhead • Latency/blocking in IO and system calls
  • 13. Vocabulary • Source • The .java text that represents a program • Bytecode • The binary version of the program that all JVMs can load and execute
  • 14. 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
  • 15. 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
  • 16. JVM 101 Java source JVM bytecode javac JVM bytecode Bytecode interpreter runs inside gather information JIT compiler triggers Native code produces executes backs off
  • 17. 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
  • 18. Inlining Instance Method Load target and arguments Target type is same as inlined? Method lookup Run target code directly Yes No Run target method as a call
  • 19. Inlining Static or Special Method Load arguments Run target code directly
  • 20. Our Tools • javac, obviously • javap to dump .class data • -XX:+PrintCompilation and
 -XX:+PrintInlining • -XX:+PrintAssembly • -XX:+LogCompilation and JITWatch
  • 21. Hello, world! • We’ll start with something simple.
  • 22. package com.headius.talks.geekout; public class HelloWorld {     public static void main(String[] args) {         System.out.println("Hello, world!");     } }
  • 23. Level 1: Bytecode • javap • Java class file disassembler • Dump structure, data, metadata, and code
  • 24. $ javap -cp dist/GeekOut.jar com.headius.talks.geekout.HelloWorld Compiled from "HelloWorld.java" public class com.headius.talks.geekout.HelloWorld { public com.headius.talks.geekout.HelloWorld(); public static void main(java.lang.String[]); }
  • 25. $ javap -cp dist/GeekOut.jar -c com.headius.talks.geekout.HelloWorld Compiled from "HelloWorld.java" public class com.headius.talks.geekout.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 }
  • 26. 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
  • 27. $ javap -cp dist/GeekOut.jar -c com.headius.talks.geekout.HelloWorld Compiled from "HelloWorld.java" public class com.headius.talks.geekout.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 }
  • 28. Level 2: Compiler Logs • -XX:+PrintCompilation • Display methods as they compile • -XX:+PrintInlining • Display inlined methods as nested
  • 29. 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”
  • 30. 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!");     } }
  • 31. $ java -Xbatch -XX:-TieredCompilation -XX:+PrintCompilation -cp dist/GeekOut.jar com.headius.talks.geekout.HelloWorld 2> /dev/null
  • 32. 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.geekout.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.geekout.HelloWorld::main @ 2 (18 bytes)
  • 33. 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.geekout.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.geekout.HelloWorld::main @ 2 (18 bytes)
  • 34. $ java -Xbatch -XX:-TieredCompilation -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining -cp dist/Geekout.jar com.headius.talks.geekout.HelloWorld 2> /dev/null
  • 35. 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.geekout.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.geekout.HelloWorld::main @ 2 (18 bytes) @ 8 com.headius.talks.geekout.HelloWorld::hello (9 bytes) already compiled into a big method
  • 36. 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.geekout.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.geekout.HelloWorld::main @ 2 (18 bytes) @ 8 com.headius.talks.geekout.HelloWorld::hello (9 bytes) already compiled into a big method
  • 37. Level 3: Native Code • -XX:+PrintAssembly • Dumps “human readable” JITed code • Google for “hotspot printassembly” • Aren’t you excited?!
  • 38. $ java -Xbatch -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -cp dist/GeekOut.jar com.headius.talks.geekout.HelloWorld 2> /dev/null | less
  • 39. Decoding compiled method 0x0000000110526110: Code: [Entry Point] [Verified Entry Point] [Constants] # {method} {0x00000001100a6420} 'hello' '()V' in 'com/headius/talks/geekout/HelloWorld' # [sp+0x70] (sp of caller) 0x0000000110526300: mov %eax,-0x14000(%rsp) 0x0000000110526307: push %rbp 0x0000000110526308: sub $0x60,%rsp ;*synchronization entry ; - com.headius.talks.geekout.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.geekout.HelloWorld::hello@0 (line 13) 0x000000011052631a: mov %r11d,0x10(%rsp) 0x000000011052631f: test %r11d,%r11d 0x0000000110526322: je 0x000000011052664e ;*invokevirtual println ; - com.headius.talks.geekout.HelloWorld::hello@5 (line 13)
  • 40. 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
  • 41. public class Tiny1 {     public static void main(String[] args) {         for (int i = 0; i < 100000; i++) {             tiny();         }     }          public static int tiny() {         return 1 + 1;     } }
  • 42. public static int tiny(); Code: 0: iconst_2 1: ireturn iconst_2: load integer 2 on stack ireturn: return int
  • 43. 110 3 b com.headius.talks.geekout.Tiny1::tiny (2 bytes) 111 4 % b com.headius.talks.geekout.Tiny1::main @ 2 (19 bytes) @ 8 com.headius.talks.geekout.Tiny1::tiny (2 bytes) inline (hot)
  • 44. {0x000000010994c3c0} 'tiny' '()I' in 'com/headius/talks/geekout/Tiny1' # [sp+0x40] (sp of caller) 0x0000000109e566a0: mov %eax,-0x14000(%rsp) 0x0000000109e566a7: push %rbp 0x0000000109e566a8: sub $0x30,%rsp ;*iconst_2 ; - com.headius.talks.geekout.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
  • 45. {0x000000010994c3c0} 'tiny' '()I' in 'com/headius/talks/geekout/Tiny1' # [sp+0x40] (sp of caller) 0x0000000109e566a0: mov %eax,-0x14000(%rsp) 0x0000000109e566a7: push %rbp 0x0000000109e566a8: sub $0x30,%rsp ;*iconst_2 ; - com.headius.talks.geekout.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
  • 46. {0x000000010e67d300} 'main' '([Ljava/lang/String;)V' in 'com/headius/talks/geekout/Tiny1' 0x000000010eb879a0: mov %eax,-0x14000(%rsp) 0x000000010eb879a7: push %rbp 0x000000010eb879a8: sub $0x40,%rsp ;*iconst_0 ; - com.headius.talks.geekout.Tiny1::main@0 (line 5) 0x000000010eb879ac: mov $0x0,%esi 0x000000010eb879b1: jmpq 0x000000010eb879c0 ;*iload_1 ; - com.headius.talks.geekout.Tiny1::main@2 (line 5) 0x000000010eb879b6: xchg %ax,%ax 0x000000010eb879b8: inc %esi ; OopMap{off=26} ;*goto ; - com.headius.talks.geekout.Tiny1::main@15 (line 5) 0x000000010eb879ba: test %eax,-0x9a08c0(%rip) # 0x000000010e1e7100 ;*goto ; - com.headius.talks.geekout.Tiny1::main@15 (line 5) ; {poll} 0x000000010eb879c0: cmp $0x186a0,%esi 0x000000010eb879c6: jl 0x000000010eb879b8 ;*if_icmpge ; - com.headius.talks.geekout.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.geekout.Tiny1::main@18 (line 8)
  • 47. 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
  • 48. 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
  • 49. 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
  • 50. 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
  • 51. 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
  • 52. 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
  • 53. 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
  • 54. 1: mov $0,%esi 2: jmpq 4: 3: inc %esi 4: cmp $1000000,%esi 5: jl 3: 6: retq
  • 56. -XX:+LogCompilation • Combines PrintCompilation and PrintInlining in one horrendous XML file • OpenJDK tool “LogCompilation” for CLI • OpenJDK tool “JITWatch” for GUI
  • 57. scopes_pcs_offset='1384' dependencies_offset='1576' handler_table_offset='1592' nul_chk_table_offset='1736' oops_offset='992' method='org/jruby/lexer/yacc/ByteArrayLexerSource$ByteArrayCursor read ()I' bytes='49' count='5296' backedge_count='1' iicount='10296' stamp='0.412'/> <writer thread='4425007104'/> <nmethod compile_id='21' compiler='C2' entry='4345862528' size='1152' address='4345862160' relocation_offset='288' insts_offset='368' stub_offset='688' scopes_data_offset='840' scopes_pcs_offset='904' dependencies_offset='1016' handler_table_offset='1032' oops_offset='784' method='org/jruby/lexer/yacc/ ByteArrayLexerSource forward (I)I' bytes='111' count='5296' backedge_count='1' iicount='10296' stamp='0.412'/> <writer thread='4300214272'/> <task_queued compile_id='22' method='org/jruby/lexer/yacc/ByteArrayLexerSource read ()I' bytes='10' count='5000' backedge_count='1' iicount='10000' stamp='0.433' comment='count' hot_count='10000'/> <writer thread='4426067968'/> <nmethod compile_id='22' compiler='C2' entry='4345885984' size='1888' address='4345885584' relocation_offset='288' insts_offset='400' stub_offset='912' scopes_data_offset='1104' scopes_pcs_offset='1496' dependencies_offset='1704' handler_table_offset='1720' nul_chk_table_offset='1864' oops_offset='1024' method='org/jruby/lexer/yacc/ByteArrayLexerSource read ()I' bytes='10' count='5044' backedge_count='1' iicount='10044' stamp='0.435'/> <writer thread='4300214272'/> <task_queued compile_id='23' method='java/util/HashMap hash (I)I' bytes='23' count='5000' backedge_count='1' iicount='10000' stamp='0.442' comment='count' hot_count='10000'/> <writer thread='4425007104'/> <nmethod compile_id='23' compiler='C2' entry='4345887808' size='440' address='4345887504' relocation_offset='288' insts_offset='304' stub_offset='368' scopes_data_offset='392' scopes_pcs_offset='400' dependencies_offset='432' method='java/util/HashMap hash (I)I' bytes='23' count='5039' backedge_count='1' iicount='10039' stamp='0.442'/> <writer thread='4300214272'/> <dependency_failed type='abstract_with_unique_concrete_subtype' ctxk='org/jruby/lexer/yacc/LexerSource' x='org/jruby/lexer/yacc/ByteArrayLexerSource' witness='org/jruby/lexer/yacc/InputStreamLexerSource' stamp='0.456'/> <dependency_failed type='abstract_with_unique_concrete_subtype' ctxk='org/jruby/lexer/yacc/LexerSource' x='org/jruby/lexer/yacc/ByteArrayLexerSource' witness='org/jruby/lexer/yacc/InputStreamLexerSource' stamp='0.456'/> <dependency_failed type='abstract_with_unique_concrete_subtype' ctxk='org/jruby/lexer/yacc/LexerSource' x='org/jruby/lexer/yacc/ByteArrayLexerSource' witness='org/jruby/lexer/yacc/InputStreamLexerSource' stamp='0.456'/> <dependency_failed type='abstract_with_unique_concrete_subtype' ctxk='org/jruby/lexer/yacc/LexerSource' x='org/jruby/lexer/yacc/ByteArrayLexerSource' witness='org/jruby/lexer/yacc/InputStreamLexerSource' stamp='0.456'/>
  • 58. $ java -jar logc.jar hotspot.log 1 java.lang.String::hashCode (67 bytes) 2 Accumulator::addSqrt (7 bytes) 3 Accumulator::sqrt (6 bytes) logc with no flags = PrintCompilation
  • 59. $ java -jar logc.jar -i hotspot.log 1 java.lang.String::hashCode (67 bytes) 2 Accumulator::addSqrt (7 bytes) @ 2 Accumulator::sqrt (6 bytes) (end time: 0.0660 nodes: 36) @ 2 java.lang.Math::sqrt (5 bytes) 3 Accumulator::sqrt (6 bytes) @ 2 java.lang.Math::sqrt (5 bytes) -i flag = PrintCompilation + PrintInlining
  • 60.
  • 61. It’s not that hard once you know what to look at.
  • 62. Part 2:The Fun Stuff
  • 63. Java Features • final fields • synchronized and volatile • string switch • lambda • single-implementer interfaces • transient objects
  • 64. #1: Final Fields • Final fields can’t be modified • The pipeline can take advantage • ...but it doesn’t always
  • 65. 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); } }
  • 66. 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");
  • 67.     private static int addHashes() {         return MY_STRING.hashCode() + MY_PROPERTY.hashCode();     }
  • 68. 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)
  • 69.     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();     }    
  • 70. 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
  • 71. 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)
  • 72. 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)
  • 73. ACHIEVEMENT UNLOCKED: Find something Hotspot could do better
  • 74. #2: Concurrency Stuff • What does “synchronized” do? • What does “volatile” do?
  • 75. 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();     } }
  • 76. 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
  • 77. 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
  • 78. 'getTime' '()J' in 'com/headius/talks/geekout/Concurrency' movabs $0x1015dbd3e,%r10 callq *%r10 ;*invokestatic currentTimeMillis ; - Concurrency::getTime@0 (line 22) retq
  • 79. 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)
  • 80. 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)
  • 81. 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)
  • 82. 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
  • 83. Volatile • Forces memory visibility, access ordering • Prevents some optimizations • Similar impact to unnecessary locking • ...but it can’t ever be removed
  • 84. 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?
  • 85. 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?
  • 86. public static Object getVariable(RubyBasicObject object, int index) { Object[] ivarTable; if (index < 0 || (ivarTable = object.varTable) == null) return null; if (ivarTable.length > index) return ivarTable[index]; return null; } Yuck!
  • 87. #3: String Switch • Added in Java 7 • ...and there was much rejoicing • But how does it really work?
  • 88. 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
  • 89. 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;         } ...
  • 90. 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 Direct branch
  • 91. switch (args.length) {     case 2000000: count = "two million"; break;     case 1000000: count = "one million"; break;     case 3000000: count = "three million"; break; }
  • 92. 49: lookupswitch { // 3 1000000: 90 2000000: 84 3000000: 96 default: 99 } Binary search
  • 93. Comparison • tableswitch is O(1) • Indexed lookup of target • lookupswitch is O(log n) • Binary search for target
  • 94. String Switch • What kind of switch do we use for String? • Table doesn’t work for hashcodes • Lookup might collide • Answer: both, plus .equals()
  • 95.     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?";         }     }
  • 96. 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... Hash and jump target for “Scala”
  • 97. 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
  • 98. 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! Scala’s index and target
  • 99.    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?";        }    }
  • 100. It’s just a hash table!
  • 101. #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
  • 102. 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);         }
  • 103.    public static void doSort(List<String> input) {        Collections.sort(input, (a,b)->Integer.compare(a.length(), b.length()));    }
  • 104. 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
  • 105. 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.
  • 106. $ javap -cp dist/GeekOut.jar -verbose -c com.headius.talks.geekout.LambdaStuff
  • 107. 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)
  • 108. 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 class files and potentially no allocation.
  • 110.     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();     }
  • 111.    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));    }
  • 112.         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));         }
  • 114.     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.geekout.LambdaStuff::getInitials@11 (line 57) Methods like map() and collect() inline...
  • 115.     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.
  • 116. 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
  • 117. Caller 1 Caller 2 Caller 3 Caller 4 sort Lambda 1 Lambda 2 Lambda 3 Lambda 4 Too many paths! JVM can’t cope!
  • 118. 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();     } Yuck!
  • 119. 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();     } Yuck! Yay!
  • 120. #5 Single-impl Interface • Interfaces are everywhere • Frequently using a common base class • Frequently single implementor of a method
  • 122. @Override public final RubyClass getMetaClass() { return metaClass; }
  • 123. public static boolean testType(RubyClass original, IRubyObject self) {
 return self.getMetaClass() == original;
 }
  • 124. 450 Bootstrap::testType (16 bytes) @ 1 IRubyObject::getMetaClass (0 bytes) (end time: 0.0000) type profile IRubyObject -> RubyArray (41%) JVM sees only target type, even though there’s one impl of method
  • 126. public static boolean testType(RubyClass original, IRubyObject self) { return ((RubyBasicObject)self).getMetaClass() == original; } Yuck!
  • 128. The JVM is not perfect.
  • 129. Every feature has a cost.
  • 130. You’ll be a better developer if you remember those facts...
  • 131. ...and you aren’t afraid to look under the covers.
  • 132. ThankYou! • Charles Oliver Nutter • @headius • headius@headius.com • http://blog.headius.com