Beyond JVM - YOW! Sydney 2013

Charles Nutter
Charles NutterProgrammer at Engine Yard
Beyond JVM
or, How to Boil the Ocean in Seven Years
Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013
+
We Like the JVM
No platform-specific
compilation needed.
No native library
dependencies
Optimizing JIT compiler
Magical black box that
runs our code
Things We Like About	

JVM
• Bytecode intermediate form	

• Freedom from native libraries	

• Optimizing JIT	

• It just works (usually)
Things That Make	

JRuby Difficult
• Bytecode intermediate form	

• Optimizing JIT	

• Freedom from native libraries	

• It just works (usually)
Things That Make	

JRuby Difficult
• Startup time sucks	

• JNI is a massive pain to use	

• Hard to get unusual languages to optimize	

• Core is in C++ that we can’t touch
Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013
There must be a way!
Startup Time
Beyond JVM - YOW! Sydney 2013
Java-Heavy JDK
• + Less native code to maintain	

• + Easier portability	

• + Easier to swap out native side	

• – Takes longer to warm up
JVM
Language

JVM
Bytecode

Bytecode
Interpreter

Bytecode
JIT
Time

Native
Code
JVM
Language

JVM
Bytecode

Bytecode
Interpreter

Bytecode
JIT

Native
Code
Save JITed Code?
• Code will change across runs	

• Often has specific memory addresses	

• May optimize object layout differently	

• Which JIT output?	

• Client, Server, Tiered (1-4)
JRuby Startup
C Ruby

JRuby

-e 1

gem --help

rake -T

0

2.5

5

7.5

10
Tweaking Flags
• -client mode	


• -XX:+TieredCompilation -XX:TieredStopAtLevel=1	


• -X-C to disable JRuby’s compiler	

• Heap sizes, code verification, etc etc
JRuby Startup
C Ruby

JRuby

JRuby (best)

-e 1

gem --help

rake -T

0

2.5

5

7.5

10
Nailgun?
• Keep a single JVM running in background	

• Toss commands over to it	

• It stays hot, so code starts faster	

• Hard to clean up all state (e.g. threads)	

• Can’t get access to user’s terminal
Drip
• Start a new JVM after each command	

• Pre-boot JVM plus optional code	

• Analyze command line for differences	

• Age out unused instances	

• https://github.com/flatland/drip
$ export JAVACMD=`which drip`	
!
$ time jruby -e 1	
!
real	 0m1.655s	
user	 0m4.486s	
sys	0m0.231s	
!
$ time jruby -e 1	
!
real	 0m0.577s	
user	 0m0.052s	
sys	0m0.065s
JRuby Startup
C Ruby

JRuby

JRuby (best)

JRuby (drip)

-e 1

gem --help

rake -T

0

2.5

5

7.5

10
$ export DRIP_INIT_CLASS=org.jruby.main.DripMain	
!
$ export DRIP_INIT=""	
!
$ time jruby -e 1	
!
real	 0m0.580s	
user	 0m0.052s	
sys	0m0.063s	
!
$ time jruby -e 1	
!
real	 0m0.155s	
user	 0m0.049s	
sys	0m0.058s
public class DripMain {!
    public static RubyInstanceConfig DRIP_CONFIG;!
    public static Ruby DRIP_RUNTIME;!

!

    public static final String JRUBY_DRIP_WARMUP_ENV = "JRUBY_DRIP_WARMUP";!
    public static final String JRUBY_DRIP_WARMUP_DEFAULT = "1 + 1";!
    public static final String JRUBY_DRIP_PREBOOT_FILE = "./dripmain.rb";!

!

    public static void main(String[] args) throws IOException {!
        // warmup JVM first!
        Ruby ruby = Ruby.newInstance();!

!

        String envWarmup = System.getenv(JRUBY_DRIP_WARMUP_ENV);!
        if (envWarmup != null && envWarmup.length() > 0) {!
            ruby.evalScriptlet(envWarmup);!
        } else {!
            ruby.evalScriptlet(JRUBY_DRIP_WARMUP_DEFAULT);!
        }!

!

        // preboot actual runtime!
        Ruby.clearGlobalRuntime();!
        File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!

!

        RubyInstanceConfig config = new RubyInstanceConfig();!
        ruby = Ruby.newInstance(config);!

!

        if (dripMain.exists()) {!
            FileInputStream fis = new FileInputStream(dripMain);!
            try {!
                ruby.getLoadService().load(dripMain.getAbsolutePath(), false);!
            } finally {!
                fis.close();!
            }!
        }!

!

        // use config and runtime from preboot process!
        DRIP_CONFIG = config;!
        DRIP_RUNTIME = ruby;!
    }!
}!
 public static final String JRUBY_DRIP_WARMUP_ENV = "JRUBY_DRI
 public static final String JRUBY_DRIP_WARMUP_DEFAULT = "1 + 1
 public static final String JRUBY_DRIP_PREBOOT_FILE = "./dripm

 public static void main(String[] args) throws IOException {!
     // warmup JVM first!
     Ruby ruby = Ruby.newInstance();!

     String envWarmup = System.getenv(JRUBY_DRIP_WARMUP_ENV);!
     if (envWarmup != null && envWarmup.length() > 0) {!
         ruby.evalScriptlet(envWarmup);!
     } else {!
         ruby.evalScriptlet(JRUBY_DRIP_WARMUP_DEFAULT);!
     }!

     // preboot actual runtime!
     Ruby.clearGlobalRuntime();!
     File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!

     RubyInstanceConfig config = new RubyInstanceConfig();!
     ruby = Ruby.newInstance(config);!
 public static final String JRUBY_DRIP_WARMUP_ENV = "JRUBY_DRI
 public static final String JRUBY_DRIP_WARMUP_DEFAULT = "1 + 1
 public static final String JRUBY_DRIP_PREBOOT_FILE = "./dripm

 public static void main(String[] args) throws IOException {!
     // warmup JVM first!
     Ruby ruby = Ruby.newInstance();!

     String envWarmup = System.getenv(JRUBY_DRIP_WARMUP_ENV);!
     if (envWarmup != null && envWarmup.length() > 0) {!
         ruby.evalScriptlet(envWarmup);!
     } else {!
         ruby.evalScriptlet(JRUBY_DRIP_WARMUP_DEFAULT);!
     }!

     // preboot actual runtime!
     Ruby.clearGlobalRuntime();!
     File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!

     RubyInstanceConfig config = new RubyInstanceConfig();!
     ruby = Ruby.newInstance(config);!
 public static final String JRUBY_DRIP_WARMUP_ENV = "JRUBY_DRI
 public static final String JRUBY_DRIP_WARMUP_DEFAULT = "1 + 1
 public static final String JRUBY_DRIP_PREBOOT_FILE = "./dripm

 public static void main(String[] args) throws IOException {!
     // warmup JVM first!
     Ruby ruby = Ruby.newInstance();!

     String envWarmup = System.getenv(JRUBY_DRIP_WARMUP_ENV);!
     if (envWarmup != null && envWarmup.length() > 0) {!
         ruby.evalScriptlet(envWarmup);!
     } else {!
         ruby.evalScriptlet(JRUBY_DRIP_WARMUP_DEFAULT);!
     }!

     // preboot actual runtime!
     Ruby.clearGlobalRuntime();!
     File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!

     RubyInstanceConfig config = new RubyInstanceConfig();!
     ruby = Ruby.newInstance(config);!
     // preboot actual runtime!
     Ruby.clearGlobalRuntime();!
     File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!

     RubyInstanceConfig config = new RubyInstanceConfig();!
     ruby = Ruby.newInstance(config);!

     if (dripMain.exists()) {!
         FileInputStream fis = new FileInputStream(dripMain);!
         try {!
             ruby.getLoadService().load(dripMain.getAbsolutePa
         } finally {!
             fis.close();!
         }!
     }!

     // use config and runtime from preboot process!
     DRIP_CONFIG = config;!
     DRIP_RUNTIME = ruby;!
 }!
     // preboot actual runtime!
     Ruby.clearGlobalRuntime();!
     File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!

     RubyInstanceConfig config = new RubyInstanceConfig();!
     ruby = Ruby.newInstance(config);!

     if (dripMain.exists()) {!
         FileInputStream fis = new FileInputStream(dripMain);!
         try {!
             ruby.getLoadService().load(dripMain.getAbsolutePa
         } finally {!
             fis.close();!
         }!
     }!

     // use config and runtime from preboot process!
     DRIP_CONFIG = config;!
     DRIP_RUNTIME = ruby;!
 }!
     // preboot actual runtime!
     Ruby.clearGlobalRuntime();!
     File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!

     RubyInstanceConfig config = new RubyInstanceConfig();!
     ruby = Ruby.newInstance(config);!

     if (dripMain.exists()) {!
         FileInputStream fis = new FileInputStream(dripMain);!
         try {!
             ruby.getLoadService().load(dripMain.getAbsolutePa
         } finally {!
             fis.close();!
         }!
     }!

     // use config and runtime from preboot process!
     DRIP_CONFIG = config;!
     DRIP_RUNTIME = ruby;!
 }!
     // preboot actual runtime!
     Ruby.clearGlobalRuntime();!
     File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!

     RubyInstanceConfig config = new RubyInstanceConfig();!
     ruby = Ruby.newInstance(config);!

     if (dripMain.exists()) {!
         FileInputStream fis = new FileInputStream(dripMain);!
         try {!
             ruby.getLoadService().load(dripMain.getAbsolutePa
         } finally {!
             fis.close();!
         }!
     }!

     // use config and runtime from preboot process!
     DRIP_CONFIG = config;!
     DRIP_RUNTIME = ruby;!
 }!
     // preboot actual runtime!
     Ruby.clearGlobalRuntime();!
     File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!

     RubyInstanceConfig config = new RubyInstanceConfig();!
     ruby = Ruby.newInstance(config);!

     if (dripMain.exists()) {!
         FileInputStream fis = new FileInputStream(dripMain);!
         try {!
             ruby.getLoadService().load(dripMain.getAbsolutePa
         } finally {!
             fis.close();!
         }!
     }!

     // use config and runtime from preboot process!
     DRIP_CONFIG = config;!
     DRIP_RUNTIME = ruby;!
 }!
JRuby Startup
C Ruby
JRuby (drip init)

JRuby

JRuby (best)

JRuby (drip)

-e 1

gem --help

rake -T

0

2.5

5

7.5

10
$ cat dripmain.rb	
# Preload some code Rails always needs	
require File.expand_path('../config/application', __FILE__)
JRuby Startup
C Ruby
JRuby (drip)

JRuby
JRuby (drip init)

JRuby (best)
JRuby (dripmain)

rake -T

0

2.5

5

7.5

10
JRuby Startup
C Ruby

JRuby (dripmain)

rake -T

0

0.275

0.55

0.825

1.1
Native Interop
JVM World

????
Native World
Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013
JNI
User Code

Java

JNI call

C/native

JNI impl
Target Library
JNI
public class GetPidJNI {!
public static native long getpid();!
!
public static void main( String[] args ) {!
getpid();!
}!
!
static {!
System.load(!
System.getProperty("user.dir") +!
"/getpidjni.dylib");!
}!
}
JNI
/* DO NOT EDIT THIS FILE - it is machine generated */!
#include <jni.h>!
/* Header for class com_headius_jnr_presentation_GetPidJNI */!
 !
#ifndef _Included_com_headius_jnr_presentation_GetPidJNI!
#define _Included_com_headius_jnr_presentation_GetPidJNI!
#ifdef __cplusplus!
extern "C" {!
#endif!
/*!
* Class:
com_headius_jnr_presentation_GetPidJNI!
* Method:
getpid!
* Signature: ()J!
*/!
JNIEXPORT jlong JNICALL Java_com_headius_jnr_1presentation_GetPidJNI_getpid!
(JNIEnv *, jclass);!
 !
#ifdef __cplusplus!
}!
#endif!
#endif
JNI
#include "com_headius_jnr_presentation_GetPidJNI.h"!
 !
jlong JNICALL Java_com_headius_jnr_1presentation_GetPidJNI_getpid!
(JNIEnv *env, jclass c) {!
 !
return getpid();!
}
JNI
$ gcc -I $JAVA_HOME/include -I
$JAVA_HOME/include/darwin -L
$JAVA_HOME/jre/lib/ -dynamiclib -ljava
-o getpidjni.dylib
com_headius_jnr_presentation_GetPidJNI.
c!
!

$ java -Djava.library.path=`pwd` -cp
target/jnr_presentation-1.0SNAPSHOT.jar
com.headius.jnr_presentation.GetPidJNI
There Must Be	

A Better Way
User Code

Java

JNI call

C/native

JNI impl
Target Library
User Code

Java

JNI call

C/native

JNI impl
Target Library
Java Native Runtime
• Java API	

• for calling Native code	

• supported by a rich Runtime library	

• You may be familiar with JNA 	

• Foreign Function Interface (FFI)	

• https://github.com/jnr
User Code
JNR stub

Java

JNI call

C/native

JNI impl
libffi
Target Library
JNR
import jnr.ffi.LibraryLoader;!
import jnr.ffi.annotations.IgnoreError;!
 !
public class GetPidJNRExample {!
public interface GetPid {!
long getpid();!
}!
!
public static void main( String[] args ) {!
GetPid getpid = LibraryLoader!
.create(GetPid.class)!
.load("c");!
!
getpid.getpid();!
}!
}
Layered Runtime
etc etc
jnr-posix	


jnr-unixsocket!
jnr-enxio

jnr-constants

jnr-ffi
jffi
libffi

jnr-x86asm
jffi Platforms
• Darwin (OS X): universal (+ppc?)	

• Linux: i386, x86_64, arm, ppc, ppc64, s390x	

• Windows: i386, x86_64	

• FreeBSD, OpenBSD: i386, x86_64	

• SunOS: i386, x86_64, sparc, sparcv9	

• AIX: ppc	

• OpenVMS, AS/400: builds out there somewhere	

• If your platform isn't here, contribute a build
jnr-ffi
• User-oriented API	

• Roughly equivalent to what JNA gives you	

• Functions, structs, callbacks, memory	

• https://github.com/jnr/jnr-ffi
jnr-posix
• Pre-bound set of POSIX functions	

• Mostly driven by what JRuby, Jython use	

• Goal: 100% of POSIX bound to Java
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
List<?

int chmod(String string, int i);!
int chown(String string, int i, int i1);!
int execv(String string, String[] strings);!
int execve(String string, String[] strings, String[] strings1);!
int fork();!
int seteuid(int i);!
int getgid();!
String getlogin();!
int getpgid();!
int getpgid(int i);!
int getpgrp();!
int getpid();!
int getppid();!
Passwd getpwent();!
Passwd getpwuid(int i);!
Passwd getpwnam(String string);!
Group getgrgid(int i);!
Group getgrnam(String string);!
int getuid();!
boolean isatty(FileDescriptor fd);!
int kill(int i, int i1);!
int symlink(String string, String string1);!
int link(String string, String string1);!
String readlink(String string) throws IOException;!
String getenv(String string);!
int setenv(String string, String string1, int i);!
int unsetenv(String string);!
int getpriority(int i, int i1);!
int setpriority(int i, int i1, int i2);!
int setuid(int i);!
FileStat stat(String string);!
int stat(String string, FileStat fs);!
int umask(int i);!
Times times();!
int utimes(String string, long[] longs, long[] longs1);!
int waitpid(int i, int[] ints, int i1);!
int wait(int[] ints);!
int errno();!
void errno(int i);!
int posix_spawnp(String string, List<? extends SpawnFileAction> list,
extends CharSequence> list1, List<? extends CharSequence> list2);
POSIX posix = POSIXFactory.getPOSIX(!
new MyPOSIXHandler(this),!
isNativeEnabled);
public interface POSIXHandler {!
public void error(Errno errno, String string);!
public void unimplementedError(String string);!
public void warn(WARNING_ID wrngd, String string, Object[] os);!
public boolean isVerbose();!
public File getCurrentWorkingDirectory();!
public String[] getEnv();!
public InputStream getInputStream();!
public PrintStream getOutputStream();!
public int getPID();!
public PrintStream getErrorStream();!
}
public
public
public
public
public
public
public
public
public

int chmod(String string, int i);!
int chown(String string, int i, int i1);!
int kill(int i, int i1);!
int getpriority(int i, int i1);!
int setpriority(int i, int i1, int i2);!
int waitpid(int i, int[] ints, int i1);!
int wait(int[] ints);!
int errno();!
void errno(int i);
jnr-constants
• C/preprocessor constants in enum form	

• Generator code to run on each platform	

• Several pregenerated sets for jnr-posix
public int open(String string, int flags, int mode);!
public int socket(int i, int i1);
jnr-enxio
• Extended Native X-platform IO	

• NIO-compatible JNR-backed IO library	

• Read, write, select (kqueue, epoll, etc)	

• Low-level fcntl control	

• https://github.com/jnr/jnr-enxio
public class NativeSocketChannel!
extends AbstractSelectableChannel!
implements ByteChannel, NativeSelectableChannel {!
public NativeSocketChannel(int fd);!
public NativeSocketChannel(int fd, int ops);!
public final int validOps();!
public final int getFD();!
public int read(ByteBuffer dst) throws IOException;!
public int write(ByteBuffer src) throws IOException!
public void shutdownInput() throws IOException;!
public void shutdownOutput() throws IOException;!
}
jnr-unixsocket
• UNIX sockets for NIO	

• Built atop jnr-enxio	

• Fully selectable, etc	

• https://github.com/jnr/jnr-unixsocket
What Else?
• NIO, NIO.2	

• Native IO, symlinks, FS-walking, 	

• Unmanaged memory	

• Selectable stdio, process IO	

• Low-level or other sockets (UNIX, ICMP, ...)	

• New APIs (graphics, crypto, OS, ...)
How Does It Perform?
Performance
• Generated code leading to JNI call	

• Generated assembly version of native part	

• jnr-x86asm: Generate and link ASM	

• Used internally by jnr	

• https://github.com/jnr/jnr-x86asm
JNA getpid

JNR getpid

getpid calls, 100M times
100000ms

10000ms

1000ms

100ms

10ms

1ms
@IgnoreError
import jnr.ffi.LibraryLoader;!
import jnr.ffi.annotations.IgnoreError;!
 !
public class GetPidJNRExample {!
public interface GetPid {!
@IgnoreError!
long getpid();!
}!
!
public static void main( String[] args ) {!
GetPid getpid = LibraryLoader!
.create(GetPid.class)!
.load("c");!
!
getpid.getpid();!
}!
}
JNR getpid

JNR getpid @IgnoreError

getpid calls, 100M times
2000ms

1500ms

1000ms

500ms

0ms
But There's More to Do
JNR getpid

JNI

JNR @IgnoreError

getpid calls, 100M times
2000ms

1500ms

1000ms

500ms

0ms

GCC -O3
JVM Help is Coming
• Standard FFI API in JDK	

• JIT intelligence	

• Drop JNI overhead where possible	

• Bind native call directly at call site	

• Security policies, segv protection, etc	

• Time for an FFI JSR
Language Performance
History
• JVM authors mentioned non-Java languages	

• Language authors have targeted JVM	

• Hundreds of JVM languages now	

• But JVM was a mismatch for many of them	

• Usually required tricks that defeated JVM
optimizations	


• Or required features JDK could not provide
JVM
Opcodes
Invocation	


Field Access	


invokevirtual!
invokeinterface!
invokestatic!
invokespecial

getfield!
setfield!
getstatic!
setstatic

Stack

Flow Control

Boolean and Numeric

Array Access	

*aload!
*astore!
b,s,c,i,l,d,f,a

Local Vars

Allocation
Goals of JSR 292
• A user-definable bytecode	

• Full freedom to define VM behavior	

• Fast method pointers + adapters	

• Optimizable like normal Java code	

• Avoid future modifications
Invoke

// Static!
System.currentTimeMillis()!
Math.log(1.0)
Invoke

// Static!
System.currentTimeMillis()!
Math.log(1.0)!
 !
// Virtual!
"hello".toUpperCase()!
System.out.println()
Invoke

// Static!
System.currentTimeMillis()!
Math.log(1.0)!
 !
// Virtual!
"hello".toUpperCase()!
System.out.println()!
 !
// Interface!
myList.add("happy happy")!
myRunnable.run()
Invoke

// Static!
System.currentTimeMillis()!
Math.log(1.0)!
 !
// Virtual!
"hello".toUpperCase()!
System.out.println()!
 !
// Interface!
myList.add("happy happy")!
myRunnable.run()!
 !
// Constructor and super!
new ArrayList()!
super.equals(other)
// Static!
invokestatic java/lang/System.currentTimeMillis:()J!
invokestatic java/lang/Math.log:(D)D!
!
// Virtual!
invokevirtual java/lang/String.toUpperCase:()Ljava/lang/String;!
invokevirtual java/io/PrintStream.println:()V!
!
// Interface!
invokeinterface java/util/List.add:(Ljava/lang/Object;)Z!
invokeinterface java/lang/Runnable.add:()V!
!
// Special!
invokespecial java/util/ArrayList.<init>:()V!
invokespecial java/lang/Object.equals:(java/lang/Object)Z
invokevirtual!
1. Confirm object is of correct type	

2. Confirm arguments are of correct type	

3. Look up method on Java class	

invokestatic
4. Cache method	

5. Invoke method

invokestatic!
1. Confirm arguments are of correct type	

2. Look up method on Java class	

3. Cache method	

4. Invoke method

invokevirtual
invokeinterface!
1. Confirm object’s type implements interface	

2. Confirm arguments are of correct type	

3. Look up method on Java class	

invokeinterface
4. Cache method	

5. Invoke method

invokespecial!
1. Confirm object is of correct type	

2. Confirm arguments are of correct type	

3. Confirm target method is visible	

4. Look up method on Java class	

5. Cache method	

6. Invoke method

invokespecial
invokedynamic!
1. Call your bootstrap code	

2. Bootstrap wires up a target function	

3. Target function invoked directly until you change it
invokedynamic bytecode
target method

bo
ot
st

ra
p

m

et
ho
d

method handles
Does It Work?
Indy Languages
• New language impls	

• JavaScript: Dyn.js and Nashorn	

• Redline Smalltalk	

• Improved language performance	

• JRuby, Groovy, Jython	

• Java features too!
JRuby/Java 6

JRuby/Java 7

Times Faster than Ruby 1.9.3
5
4.32

3.75

3.66
3.44

2.5

2.658

1.914

1.25

0

1.346

base64

1.565

1.538

richards

neural

redblack
red/black tree, pure Ruby versus native

ruby-2.0.0 + Ruby

2.48s

ruby-2.0.0 + C ext

0.51s

jruby + Ruby

0.29s

0

0.75

1.5
Runtime per iteration

2.25

3
Caveat Emptor
• Indy was really slow in first Java 7 release	

• Got fast in 7u2...and turned out broken	

• Rewritten for 7u40	

• Slow to warm up	

• Still some issues (memory use, etc)	

• Java 8 due in March…
All That C++
JVM
Language

JVM
Bytecode

Out of our control	

Written in C++

Bytecode
Interpreter

Bytecode
JIT

Native
Code
What If…
• The JVM’s JIT optimizer were written in Java	

• You could customize how the JIT works for
your language or library	


• JITed code could directly make native calls
Graal
• A 100% Java-based JIT framework	

• Grew out of the 100% Java “Maxine” JVM	

• Backends to assembly or HotSpot IR	

• Directly control code generation	

• Build a language without using JVM bytecode	

• http://openjdk.java.net/projects/graal/
JVM
Language
Plain Java APIs

Graal	

Intermediate
Representation

Graal
Optimizer

Your
Optimizations
Under your control

Native
Code
However…
• Not everyone is a compiler writer	

• Graal’s IR is low-level and nontrivial	

• Need to understand JVM internals	

• Need some understanding of CPU
The Dream
• Design your language	

• ???	

• PROFIT
What We Want
• Design your language	

• Write an interpreter	

• PROFIT
Truffle
• Language framework built on Graal	

• Designed to fulfill the dream	

• Implement interpreter	

• Truffle feeds that to backend	

• No compiler expertise needed	


• https://wiki.openjdk.java.net/display/Graal/Truffle+FAQ+and+Guidelines
JVM
Language

Truffle	

AST
All we need

Graal
Intermediate
Representation

Graal
Optimizer

Native
Code
Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013
What Have We Learned?
The JVM has its
problems, but we can
fix them.
OpenJDK and all these
solutions are really,
truly, open source.
Nothing is impossible.
Thank you!
• Charles Oliver Nutter	

• @headius, headius@headius.com	

• http://blog.headius.com
1 of 115

Recommended

JVM for Dummies - OSCON 2011 by
JVM for Dummies - OSCON 2011JVM for Dummies - OSCON 2011
JVM for Dummies - OSCON 2011Charles Nutter
7.7K views209 slides
Fast as C: How to Write Really Terrible Java by
Fast as C: How to Write Really Terrible JavaFast as C: How to Write Really Terrible Java
Fast as C: How to Write Really Terrible JavaCharles Nutter
10.6K views132 slides
JRuby and Invokedynamic - Japan JUG 2015 by
JRuby and Invokedynamic - Japan JUG 2015JRuby and Invokedynamic - Japan JUG 2015
JRuby and Invokedynamic - Japan JUG 2015Charles Nutter
1.6K views89 slides
Down the Rabbit Hole: An Adventure in JVM Wonderland by
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
2.6K views128 slides
JavaOne 2011 - JVM Bytecode for Dummies by
JavaOne 2011 - JVM Bytecode for DummiesJavaOne 2011 - JVM Bytecode for Dummies
JavaOne 2011 - JVM Bytecode for DummiesCharles Nutter
8K views141 slides
JavaOne 2012 - JVM JIT for Dummies by
JavaOne 2012 - JVM JIT for DummiesJavaOne 2012 - JVM JIT for Dummies
JavaOne 2012 - JVM JIT for DummiesCharles Nutter
11K views123 slides

More Related Content

What's hot

Mastering java bytecode with ASM - GeeCON 2012 by
Mastering java bytecode with ASM - GeeCON 2012Mastering java bytecode with ASM - GeeCON 2012
Mastering java bytecode with ASM - GeeCON 2012Anton Arhipov
5.3K views119 slides
JRuby 9000 - Optimizing Above the JVM by
JRuby 9000 - Optimizing Above the JVMJRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVMCharles Nutter
2.1K views65 slides
JRuby 9000 - Taipei Ruby User's Group 2015 by
JRuby 9000 - Taipei Ruby User's Group 2015JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015Charles Nutter
1.2K views73 slides
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ... by
Ø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
8.5K views107 slides
Beyond JVM - YOW Melbourne 2013 by
Beyond JVM - YOW Melbourne 2013Beyond JVM - YOW Melbourne 2013
Beyond JVM - YOW Melbourne 2013Charles Nutter
3.3K views115 slides
Inside the JVM - Follow the white rabbit! by
Inside the JVM - Follow the white rabbit!Inside the JVM - Follow the white rabbit!
Inside the JVM - Follow the white rabbit!Sylvain Wallez
1.5K views59 slides

What's hot(20)

Mastering java bytecode with ASM - GeeCON 2012 by Anton Arhipov
Mastering java bytecode with ASM - GeeCON 2012Mastering java bytecode with ASM - GeeCON 2012
Mastering java bytecode with ASM - GeeCON 2012
Anton Arhipov5.3K views
JRuby 9000 - Optimizing Above the JVM by Charles Nutter
JRuby 9000 - Optimizing Above the JVMJRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVM
Charles Nutter2.1K views
JRuby 9000 - Taipei Ruby User's Group 2015 by Charles Nutter
JRuby 9000 - Taipei Ruby User's Group 2015JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015
Charles Nutter1.2K views
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ... by Charles Nutter
Ø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 Nutter8.5K views
Beyond JVM - YOW Melbourne 2013 by Charles Nutter
Beyond JVM - YOW Melbourne 2013Beyond JVM - YOW Melbourne 2013
Beyond JVM - YOW Melbourne 2013
Charles Nutter3.3K views
Inside the JVM - Follow the white rabbit! by Sylvain Wallez
Inside the JVM - Follow the white rabbit!Inside the JVM - Follow the white rabbit!
Inside the JVM - Follow the white rabbit!
Sylvain Wallez1.5K views
Oscon Java Testing on the Fast Lane by Andres Almiray
Oscon Java Testing on the Fast LaneOscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast Lane
Andres Almiray3.9K views
Mastering Java Bytecode - JAX.de 2012 by Anton Arhipov
Mastering Java Bytecode - JAX.de 2012Mastering Java Bytecode - JAX.de 2012
Mastering Java Bytecode - JAX.de 2012
Anton Arhipov2.6K views
Concurrency in Python by Mosky Liu
Concurrency in PythonConcurrency in Python
Concurrency in Python
Mosky Liu1.3K views
JRuby @ Boulder Ruby by Nick Sieger
JRuby @ Boulder RubyJRuby @ Boulder Ruby
JRuby @ Boulder Ruby
Nick Sieger791 views
The Enterprise Strikes Back by Burke Libbey
The Enterprise Strikes BackThe Enterprise Strikes Back
The Enterprise Strikes Back
Burke Libbey1.2K views
Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015) by ngotogenome
Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)
Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)
ngotogenome11.9K views
Clojure in real life 17.10.2014 by Metosin Oy
Clojure in real life 17.10.2014Clojure in real life 17.10.2014
Clojure in real life 17.10.2014
Metosin Oy3.6K views
Supercharging reflective libraries with InvokeDynamic by Ian Robertson
Supercharging reflective libraries with InvokeDynamicSupercharging reflective libraries with InvokeDynamic
Supercharging reflective libraries with InvokeDynamic
Ian Robertson1.4K views
Using Java from Ruby with JRuby IRB by Hiro Asari
Using Java from Ruby with JRuby IRBUsing Java from Ruby with JRuby IRB
Using Java from Ruby with JRuby IRB
Hiro Asari5K views
Практики применения JRuby by .toster
Практики применения JRubyПрактики применения JRuby
Практики применения JRuby
.toster967 views
The Art of JVM Profiling by Andrei Pangin
The Art of JVM ProfilingThe Art of JVM Profiling
The Art of JVM Profiling
Andrei Pangin813 views
Everything you wanted to know about Stack Traces and Heap Dumps by Andrei Pangin
Everything you wanted to know about Stack Traces and Heap DumpsEverything you wanted to know about Stack Traces and Heap Dumps
Everything you wanted to know about Stack Traces and Heap Dumps
Andrei Pangin2.6K views
Java Serialization Facts and Fallacies by Roman Elizarov
Java Serialization Facts and FallaciesJava Serialization Facts and Fallacies
Java Serialization Facts and Fallacies
Roman Elizarov5.9K views

Similar to Beyond JVM - YOW! Sydney 2013

JRoR Deploying Rails on JRuby by
JRoR Deploying Rails on JRubyJRoR Deploying Rails on JRuby
JRoR Deploying Rails on JRubyelliando dias
810 views28 slides
Developing cross platform desktop application with Ruby by
Developing cross platform desktop application with RubyDeveloping cross platform desktop application with Ruby
Developing cross platform desktop application with RubyAnis Ahmad
18.9K views54 slides
Beyond JVM - YOW! Brisbane 2013 by
Beyond JVM - YOW! Brisbane 2013Beyond JVM - YOW! Brisbane 2013
Beyond JVM - YOW! Brisbane 2013Charles Nutter
1.8K views88 slides
JRuby - Enterprise 2.0 by
JRuby - Enterprise 2.0JRuby - Enterprise 2.0
JRuby - Enterprise 2.0Jan Sifra
2.9K views32 slides
Jruby synergy-of-ruby-and-java by
Jruby synergy-of-ruby-and-javaJruby synergy-of-ruby-and-java
Jruby synergy-of-ruby-and-javaKeith Bennett
1.1K views21 slides
Introduction to NodeJS with LOLCats by
Introduction to NodeJS with LOLCatsIntroduction to NodeJS with LOLCats
Introduction to NodeJS with LOLCatsDerek Anderson
1.2K views31 slides

Similar to Beyond JVM - YOW! Sydney 2013(20)

JRoR Deploying Rails on JRuby by elliando dias
JRoR Deploying Rails on JRubyJRoR Deploying Rails on JRuby
JRoR Deploying Rails on JRuby
elliando dias810 views
Developing cross platform desktop application with Ruby by Anis Ahmad
Developing cross platform desktop application with RubyDeveloping cross platform desktop application with Ruby
Developing cross platform desktop application with Ruby
Anis Ahmad18.9K views
Beyond JVM - YOW! Brisbane 2013 by Charles Nutter
Beyond JVM - YOW! Brisbane 2013Beyond JVM - YOW! Brisbane 2013
Beyond JVM - YOW! Brisbane 2013
Charles Nutter1.8K views
JRuby - Enterprise 2.0 by Jan Sifra
JRuby - Enterprise 2.0JRuby - Enterprise 2.0
JRuby - Enterprise 2.0
Jan Sifra2.9K views
Jruby synergy-of-ruby-and-java by Keith Bennett
Jruby synergy-of-ruby-and-javaJruby synergy-of-ruby-and-java
Jruby synergy-of-ruby-and-java
Keith Bennett1.1K views
Introduction to NodeJS with LOLCats by Derek Anderson
Introduction to NodeJS with LOLCatsIntroduction to NodeJS with LOLCats
Introduction to NodeJS with LOLCats
Derek Anderson1.2K views
Building web framework with Rack by sickill
Building web framework with RackBuilding web framework with Rack
Building web framework with Rack
sickill3.6K views
MongoDB Munich 2012: MongoDB for official documents in Bavaria by MongoDB
MongoDB Munich 2012: MongoDB for official documents in BavariaMongoDB Munich 2012: MongoDB for official documents in Bavaria
MongoDB Munich 2012: MongoDB for official documents in Bavaria
MongoDB924 views
Iron Languages - NYC CodeCamp 2/19/2011 by Jimmy Schementi
Iron Languages - NYC CodeCamp 2/19/2011Iron Languages - NYC CodeCamp 2/19/2011
Iron Languages - NYC CodeCamp 2/19/2011
Jimmy Schementi1.1K views
One commit, one release. Continuously delivering a Symfony project. by Javier López
One commit, one release. Continuously delivering a Symfony project.One commit, one release. Continuously delivering a Symfony project.
One commit, one release. Continuously delivering a Symfony project.
Javier López3.2K views
Beginner's Guide to the nmap Scripting Engine - Redspin Engineer, David Shaw by Redspin, Inc.
Beginner's Guide to the nmap Scripting Engine - Redspin Engineer, David ShawBeginner's Guide to the nmap Scripting Engine - Redspin Engineer, David Shaw
Beginner's Guide to the nmap Scripting Engine - Redspin Engineer, David Shaw
Redspin, Inc.1.1K views
RichFaces - Testing on Mobile Devices by Pavol Pitoňák
RichFaces - Testing on Mobile DevicesRichFaces - Testing on Mobile Devices
RichFaces - Testing on Mobile Devices
Pavol Pitoňák12.4K views
GeeCON 2017 - TestContainers. Integration testing without the hassle by Anton Arhipov
GeeCON 2017 - TestContainers. Integration testing without the hassleGeeCON 2017 - TestContainers. Integration testing without the hassle
GeeCON 2017 - TestContainers. Integration testing without the hassle
Anton Arhipov5.4K views
Replacing Oracle with MongoDB for a templating application at the Bavarian go... by Comsysto Reply GmbH
Replacing Oracle with MongoDB for a templating application at the Bavarian go...Replacing Oracle with MongoDB for a templating application at the Bavarian go...
Replacing Oracle with MongoDB for a templating application at the Bavarian go...
Real-world polyglot programming on the JVM - Ben Summers (ONEIS) by jaxLondonConference
Real-world polyglot programming on the JVM  - Ben Summers (ONEIS)Real-world polyglot programming on the JVM  - Ben Summers (ONEIS)
Real-world polyglot programming on the JVM - Ben Summers (ONEIS)

More from Charles Nutter

The Year of JRuby - RubyC 2018 by
The Year of JRuby - RubyC 2018The Year of JRuby - RubyC 2018
The Year of JRuby - RubyC 2018Charles Nutter
860 views61 slides
Open Source Software Needs You! by
Open Source Software Needs You!Open Source Software Needs You!
Open Source Software Needs You!Charles Nutter
2.4K views86 slides
InvokeBinder: Fluent Programming for Method Handles by
InvokeBinder: Fluent Programming for Method HandlesInvokeBinder: Fluent Programming for Method Handles
InvokeBinder: Fluent Programming for Method HandlesCharles Nutter
2.3K views64 slides
Over 9000: JRuby in 2015 by
Over 9000: JRuby in 2015Over 9000: JRuby in 2015
Over 9000: JRuby in 2015Charles Nutter
7.9K views117 slides
Doing Open Source the Right Way by
Doing Open Source the Right WayDoing Open Source the Right Way
Doing Open Source the Right WayCharles Nutter
2.3K views82 slides
JRuby: The Hard Parts by
JRuby: The Hard PartsJRuby: The Hard Parts
JRuby: The Hard PartsCharles Nutter
2.8K views71 slides

More from Charles Nutter(18)

The Year of JRuby - RubyC 2018 by Charles Nutter
The Year of JRuby - RubyC 2018The Year of JRuby - RubyC 2018
The Year of JRuby - RubyC 2018
Charles Nutter860 views
Open Source Software Needs You! by Charles Nutter
Open Source Software Needs You!Open Source Software Needs You!
Open Source Software Needs You!
Charles Nutter2.4K views
InvokeBinder: Fluent Programming for Method Handles by Charles Nutter
InvokeBinder: Fluent Programming for Method HandlesInvokeBinder: Fluent Programming for Method Handles
InvokeBinder: Fluent Programming for Method Handles
Charles Nutter2.3K views
Doing Open Source the Right Way by Charles Nutter
Doing Open Source the Right WayDoing Open Source the Right Way
Doing Open Source the Right Way
Charles Nutter2.3K views
Bringing Concurrency to Ruby - RubyConf India 2014 by Charles Nutter
Bringing Concurrency to Ruby - RubyConf India 2014Bringing Concurrency to Ruby - RubyConf India 2014
Bringing Concurrency to Ruby - RubyConf India 2014
Charles Nutter4.9K views
The Future of JRuby - Baruco 2013 by Charles Nutter
The Future of JRuby - Baruco 2013The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013
Charles Nutter3.2K views
High Performance Ruby - E4E Conference 2013 by Charles Nutter
High Performance Ruby - E4E Conference 2013High Performance Ruby - E4E Conference 2013
High Performance Ruby - E4E Conference 2013
Charles Nutter5K views
Invokedynamic: Tales from the Trenches by Charles Nutter
Invokedynamic: Tales from the TrenchesInvokedynamic: Tales from the Trenches
Invokedynamic: Tales from the Trenches
Charles Nutter2.2K views
Why JRuby? - RubyConf 2012 by Charles Nutter
Why JRuby? - RubyConf 2012Why JRuby? - RubyConf 2012
Why JRuby? - RubyConf 2012
Charles Nutter1.8K views
Aloha RubyConf 2012 - JRuby by Charles Nutter
Aloha RubyConf 2012 - JRubyAloha RubyConf 2012 - JRuby
Aloha RubyConf 2012 - JRuby
Charles Nutter2.4K views
High Performance Ruby - Golden Gate RubyConf 2012 by Charles Nutter
High Performance Ruby - Golden Gate RubyConf 2012High Performance Ruby - Golden Gate RubyConf 2012
High Performance Ruby - Golden Gate RubyConf 2012
Charles Nutter9K views
InvokeDynamic - You Ain't Seen Nothin Yet by Charles Nutter
InvokeDynamic - You Ain't Seen Nothin YetInvokeDynamic - You Ain't Seen Nothin Yet
InvokeDynamic - You Ain't Seen Nothin Yet
Charles Nutter3.6K views
Building Languages for the JVM - StarTechConf 2011 by Charles Nutter
Building Languages for the JVM - StarTechConf 2011Building Languages for the JVM - StarTechConf 2011
Building Languages for the JVM - StarTechConf 2011
Charles Nutter1.6K views
JRuby: What's Different (RORO Melbourne October 2011) by Charles Nutter
JRuby: What's Different (RORO Melbourne October 2011)JRuby: What's Different (RORO Melbourne October 2011)
JRuby: What's Different (RORO Melbourne October 2011)
Charles Nutter610 views

Recently uploaded

ChatGPT and AI for Web Developers by
ChatGPT and AI for Web DevelopersChatGPT and AI for Web Developers
ChatGPT and AI for Web DevelopersMaximiliano Firtman
181 views82 slides
Business Analyst Series 2023 - Week 3 Session 5 by
Business Analyst Series 2023 -  Week 3 Session 5Business Analyst Series 2023 -  Week 3 Session 5
Business Analyst Series 2023 - Week 3 Session 5DianaGray10
209 views20 slides
PharoJS - Zürich Smalltalk Group Meetup November 2023 by
PharoJS - Zürich Smalltalk Group Meetup November 2023PharoJS - Zürich Smalltalk Group Meetup November 2023
PharoJS - Zürich Smalltalk Group Meetup November 2023Noury Bouraqadi
120 views17 slides
Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen... by
Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen...Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen...
Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen...NUS-ISS
28 views70 slides
STPI OctaNE CoE Brochure.pdf by
STPI OctaNE CoE Brochure.pdfSTPI OctaNE CoE Brochure.pdf
STPI OctaNE CoE Brochure.pdfmadhurjyapb
12 views1 slide
SAP Automation Using Bar Code and FIORI.pdf by
SAP Automation Using Bar Code and FIORI.pdfSAP Automation Using Bar Code and FIORI.pdf
SAP Automation Using Bar Code and FIORI.pdfVirendra Rai, PMP
19 views38 slides

Recently uploaded(20)

Business Analyst Series 2023 - Week 3 Session 5 by DianaGray10
Business Analyst Series 2023 -  Week 3 Session 5Business Analyst Series 2023 -  Week 3 Session 5
Business Analyst Series 2023 - Week 3 Session 5
DianaGray10209 views
PharoJS - Zürich Smalltalk Group Meetup November 2023 by Noury Bouraqadi
PharoJS - Zürich Smalltalk Group Meetup November 2023PharoJS - Zürich Smalltalk Group Meetup November 2023
PharoJS - Zürich Smalltalk Group Meetup November 2023
Noury Bouraqadi120 views
Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen... by NUS-ISS
Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen...Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen...
Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen...
NUS-ISS28 views
STPI OctaNE CoE Brochure.pdf by madhurjyapb
STPI OctaNE CoE Brochure.pdfSTPI OctaNE CoE Brochure.pdf
STPI OctaNE CoE Brochure.pdf
madhurjyapb12 views
SAP Automation Using Bar Code and FIORI.pdf by Virendra Rai, PMP
SAP Automation Using Bar Code and FIORI.pdfSAP Automation Using Bar Code and FIORI.pdf
SAP Automation Using Bar Code and FIORI.pdf
How to reduce cold starts for Java Serverless applications in AWS at JCON Wor... by Vadym Kazulkin
How to reduce cold starts for Java Serverless applications in AWS at JCON Wor...How to reduce cold starts for Java Serverless applications in AWS at JCON Wor...
How to reduce cold starts for Java Serverless applications in AWS at JCON Wor...
Vadym Kazulkin75 views
Future of Learning - Khoong Chan Meng by NUS-ISS
Future of Learning - Khoong Chan MengFuture of Learning - Khoong Chan Meng
Future of Learning - Khoong Chan Meng
NUS-ISS33 views
Spesifikasi Lengkap ASUS Vivobook Go 14 by Dot Semarang
Spesifikasi Lengkap ASUS Vivobook Go 14Spesifikasi Lengkap ASUS Vivobook Go 14
Spesifikasi Lengkap ASUS Vivobook Go 14
Dot Semarang35 views
Combining Orchestration and Choreography for a Clean Architecture by ThomasHeinrichs1
Combining Orchestration and Choreography for a Clean ArchitectureCombining Orchestration and Choreography for a Clean Architecture
Combining Orchestration and Choreography for a Clean Architecture
ThomasHeinrichs169 views
.conf Go 2023 - How KPN drives Customer Satisfaction on IPTV by Splunk
.conf Go 2023 - How KPN drives Customer Satisfaction on IPTV.conf Go 2023 - How KPN drives Customer Satisfaction on IPTV
.conf Go 2023 - How KPN drives Customer Satisfaction on IPTV
Splunk88 views
DALI Basics Course 2023 by Ivory Egg
DALI Basics Course  2023DALI Basics Course  2023
DALI Basics Course 2023
Ivory Egg14 views
Special_edition_innovator_2023.pdf by WillDavies22
Special_edition_innovator_2023.pdfSpecial_edition_innovator_2023.pdf
Special_edition_innovator_2023.pdf
WillDavies2216 views
Digital Product-Centric Enterprise and Enterprise Architecture - Tan Eng Tsze by NUS-ISS
Digital Product-Centric Enterprise and Enterprise Architecture - Tan Eng TszeDigital Product-Centric Enterprise and Enterprise Architecture - Tan Eng Tsze
Digital Product-Centric Enterprise and Enterprise Architecture - Tan Eng Tsze
NUS-ISS19 views
[2023] Putting the R! in R&D.pdf by Eleanor McHugh
[2023] Putting the R! in R&D.pdf[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf
Eleanor McHugh38 views
Five Things You SHOULD Know About Postman by Postman
Five Things You SHOULD Know About PostmanFive Things You SHOULD Know About Postman
Five Things You SHOULD Know About Postman
Postman27 views
Data-centric AI and the convergence of data and model engineering: opportunit... by Paolo Missier
Data-centric AI and the convergence of data and model engineering:opportunit...Data-centric AI and the convergence of data and model engineering:opportunit...
Data-centric AI and the convergence of data and model engineering: opportunit...
Paolo Missier34 views

Beyond JVM - YOW! Sydney 2013

  • 1. Beyond JVM or, How to Boil the Ocean in Seven Years
  • 4. +
  • 9. Magical black box that runs our code
  • 10. Things We Like About JVM • Bytecode intermediate form • Freedom from native libraries • Optimizing JIT • It just works (usually)
  • 11. Things That Make JRuby Difficult • Bytecode intermediate form • Optimizing JIT • Freedom from native libraries • It just works (usually)
  • 12. Things That Make JRuby Difficult • Startup time sucks • JNI is a massive pain to use • Hard to get unusual languages to optimize • Core is in C++ that we can’t touch
  • 18. There must be a way!
  • 21. Java-Heavy JDK • + Less native code to maintain • + Easier portability • + Easier to swap out native side • – Takes longer to warm up
  • 24. Save JITed Code? • Code will change across runs • Often has specific memory addresses • May optimize object layout differently • Which JIT output? • Client, Server, Tiered (1-4)
  • 25. JRuby Startup C Ruby JRuby -e 1 gem --help rake -T 0 2.5 5 7.5 10
  • 26. Tweaking Flags • -client mode • -XX:+TieredCompilation -XX:TieredStopAtLevel=1 • -X-C to disable JRuby’s compiler • Heap sizes, code verification, etc etc
  • 27. JRuby Startup C Ruby JRuby JRuby (best) -e 1 gem --help rake -T 0 2.5 5 7.5 10
  • 28. Nailgun? • Keep a single JVM running in background • Toss commands over to it • It stays hot, so code starts faster • Hard to clean up all state (e.g. threads) • Can’t get access to user’s terminal
  • 29. Drip • Start a new JVM after each command • Pre-boot JVM plus optional code • Analyze command line for differences • Age out unused instances • https://github.com/flatland/drip
  • 30. $ export JAVACMD=`which drip` ! $ time jruby -e 1 ! real 0m1.655s user 0m4.486s sys 0m0.231s ! $ time jruby -e 1 ! real 0m0.577s user 0m0.052s sys 0m0.065s
  • 31. JRuby Startup C Ruby JRuby JRuby (best) JRuby (drip) -e 1 gem --help rake -T 0 2.5 5 7.5 10
  • 32. $ export DRIP_INIT_CLASS=org.jruby.main.DripMain ! $ export DRIP_INIT="" ! $ time jruby -e 1 ! real 0m0.580s user 0m0.052s sys 0m0.063s ! $ time jruby -e 1 ! real 0m0.155s user 0m0.049s sys 0m0.058s
  • 33. public class DripMain {!     public static RubyInstanceConfig DRIP_CONFIG;!     public static Ruby DRIP_RUNTIME;! !     public static final String JRUBY_DRIP_WARMUP_ENV = "JRUBY_DRIP_WARMUP";!     public static final String JRUBY_DRIP_WARMUP_DEFAULT = "1 + 1";!     public static final String JRUBY_DRIP_PREBOOT_FILE = "./dripmain.rb";! !     public static void main(String[] args) throws IOException {!         // warmup JVM first!         Ruby ruby = Ruby.newInstance();! !         String envWarmup = System.getenv(JRUBY_DRIP_WARMUP_ENV);!         if (envWarmup != null && envWarmup.length() > 0) {!             ruby.evalScriptlet(envWarmup);!         } else {!             ruby.evalScriptlet(JRUBY_DRIP_WARMUP_DEFAULT);!         }! !         // preboot actual runtime!         Ruby.clearGlobalRuntime();!         File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);! !         RubyInstanceConfig config = new RubyInstanceConfig();!         ruby = Ruby.newInstance(config);! !         if (dripMain.exists()) {!             FileInputStream fis = new FileInputStream(dripMain);!             try {!                 ruby.getLoadService().load(dripMain.getAbsolutePath(), false);!             } finally {!                 fis.close();!             }!         }! !         // use config and runtime from preboot process!         DRIP_CONFIG = config;!         DRIP_RUNTIME = ruby;!     }! }!
  • 34.  public static final String JRUBY_DRIP_WARMUP_ENV = "JRUBY_DRI  public static final String JRUBY_DRIP_WARMUP_DEFAULT = "1 + 1  public static final String JRUBY_DRIP_PREBOOT_FILE = "./dripm  public static void main(String[] args) throws IOException {!      // warmup JVM first!      Ruby ruby = Ruby.newInstance();!      String envWarmup = System.getenv(JRUBY_DRIP_WARMUP_ENV);!      if (envWarmup != null && envWarmup.length() > 0) {!          ruby.evalScriptlet(envWarmup);!      } else {!          ruby.evalScriptlet(JRUBY_DRIP_WARMUP_DEFAULT);!      }!      // preboot actual runtime!      Ruby.clearGlobalRuntime();!      File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!      RubyInstanceConfig config = new RubyInstanceConfig();!      ruby = Ruby.newInstance(config);!
  • 35.  public static final String JRUBY_DRIP_WARMUP_ENV = "JRUBY_DRI  public static final String JRUBY_DRIP_WARMUP_DEFAULT = "1 + 1  public static final String JRUBY_DRIP_PREBOOT_FILE = "./dripm  public static void main(String[] args) throws IOException {!      // warmup JVM first!      Ruby ruby = Ruby.newInstance();!      String envWarmup = System.getenv(JRUBY_DRIP_WARMUP_ENV);!      if (envWarmup != null && envWarmup.length() > 0) {!          ruby.evalScriptlet(envWarmup);!      } else {!          ruby.evalScriptlet(JRUBY_DRIP_WARMUP_DEFAULT);!      }!      // preboot actual runtime!      Ruby.clearGlobalRuntime();!      File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!      RubyInstanceConfig config = new RubyInstanceConfig();!      ruby = Ruby.newInstance(config);!
  • 36.  public static final String JRUBY_DRIP_WARMUP_ENV = "JRUBY_DRI  public static final String JRUBY_DRIP_WARMUP_DEFAULT = "1 + 1  public static final String JRUBY_DRIP_PREBOOT_FILE = "./dripm  public static void main(String[] args) throws IOException {!      // warmup JVM first!      Ruby ruby = Ruby.newInstance();!      String envWarmup = System.getenv(JRUBY_DRIP_WARMUP_ENV);!      if (envWarmup != null && envWarmup.length() > 0) {!          ruby.evalScriptlet(envWarmup);!      } else {!          ruby.evalScriptlet(JRUBY_DRIP_WARMUP_DEFAULT);!      }!      // preboot actual runtime!      Ruby.clearGlobalRuntime();!      File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!      RubyInstanceConfig config = new RubyInstanceConfig();!      ruby = Ruby.newInstance(config);!
  • 37.      // preboot actual runtime!      Ruby.clearGlobalRuntime();!      File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!      RubyInstanceConfig config = new RubyInstanceConfig();!      ruby = Ruby.newInstance(config);!      if (dripMain.exists()) {!          FileInputStream fis = new FileInputStream(dripMain);!          try {!              ruby.getLoadService().load(dripMain.getAbsolutePa          } finally {!              fis.close();!          }!      }!      // use config and runtime from preboot process!      DRIP_CONFIG = config;!      DRIP_RUNTIME = ruby;!  }!
  • 38.      // preboot actual runtime!      Ruby.clearGlobalRuntime();!      File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!      RubyInstanceConfig config = new RubyInstanceConfig();!      ruby = Ruby.newInstance(config);!      if (dripMain.exists()) {!          FileInputStream fis = new FileInputStream(dripMain);!          try {!              ruby.getLoadService().load(dripMain.getAbsolutePa          } finally {!              fis.close();!          }!      }!      // use config and runtime from preboot process!      DRIP_CONFIG = config;!      DRIP_RUNTIME = ruby;!  }!
  • 39.      // preboot actual runtime!      Ruby.clearGlobalRuntime();!      File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!      RubyInstanceConfig config = new RubyInstanceConfig();!      ruby = Ruby.newInstance(config);!      if (dripMain.exists()) {!          FileInputStream fis = new FileInputStream(dripMain);!          try {!              ruby.getLoadService().load(dripMain.getAbsolutePa          } finally {!              fis.close();!          }!      }!      // use config and runtime from preboot process!      DRIP_CONFIG = config;!      DRIP_RUNTIME = ruby;!  }!
  • 40.      // preboot actual runtime!      Ruby.clearGlobalRuntime();!      File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!      RubyInstanceConfig config = new RubyInstanceConfig();!      ruby = Ruby.newInstance(config);!      if (dripMain.exists()) {!          FileInputStream fis = new FileInputStream(dripMain);!          try {!              ruby.getLoadService().load(dripMain.getAbsolutePa          } finally {!              fis.close();!          }!      }!      // use config and runtime from preboot process!      DRIP_CONFIG = config;!      DRIP_RUNTIME = ruby;!  }!
  • 41.      // preboot actual runtime!      Ruby.clearGlobalRuntime();!      File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!      RubyInstanceConfig config = new RubyInstanceConfig();!      ruby = Ruby.newInstance(config);!      if (dripMain.exists()) {!          FileInputStream fis = new FileInputStream(dripMain);!          try {!              ruby.getLoadService().load(dripMain.getAbsolutePa          } finally {!              fis.close();!          }!      }!      // use config and runtime from preboot process!      DRIP_CONFIG = config;!      DRIP_RUNTIME = ruby;!  }!
  • 42. JRuby Startup C Ruby JRuby (drip init) JRuby JRuby (best) JRuby (drip) -e 1 gem --help rake -T 0 2.5 5 7.5 10
  • 43. $ cat dripmain.rb # Preload some code Rails always needs require File.expand_path('../config/application', __FILE__)
  • 44. JRuby Startup C Ruby JRuby (drip) JRuby JRuby (drip init) JRuby (best) JRuby (dripmain) rake -T 0 2.5 5 7.5 10
  • 45. JRuby Startup C Ruby JRuby (dripmain) rake -T 0 0.275 0.55 0.825 1.1
  • 50. JNI
  • 52. JNI public class GetPidJNI {! public static native long getpid();! ! public static void main( String[] args ) {! getpid();! }! ! static {! System.load(! System.getProperty("user.dir") +! "/getpidjni.dylib");! }! }
  • 53. JNI /* DO NOT EDIT THIS FILE - it is machine generated */! #include <jni.h>! /* Header for class com_headius_jnr_presentation_GetPidJNI */!  ! #ifndef _Included_com_headius_jnr_presentation_GetPidJNI! #define _Included_com_headius_jnr_presentation_GetPidJNI! #ifdef __cplusplus! extern "C" {! #endif! /*! * Class: com_headius_jnr_presentation_GetPidJNI! * Method: getpid! * Signature: ()J! */! JNIEXPORT jlong JNICALL Java_com_headius_jnr_1presentation_GetPidJNI_getpid! (JNIEnv *, jclass);!  ! #ifdef __cplusplus! }! #endif! #endif
  • 54. JNI #include "com_headius_jnr_presentation_GetPidJNI.h"!  ! jlong JNICALL Java_com_headius_jnr_1presentation_GetPidJNI_getpid! (JNIEnv *env, jclass c) {!  ! return getpid();! }
  • 55. JNI $ gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -L $JAVA_HOME/jre/lib/ -dynamiclib -ljava -o getpidjni.dylib com_headius_jnr_presentation_GetPidJNI. c! ! $ java -Djava.library.path=`pwd` -cp target/jnr_presentation-1.0SNAPSHOT.jar com.headius.jnr_presentation.GetPidJNI
  • 56. There Must Be A Better Way
  • 59. Java Native Runtime • Java API • for calling Native code • supported by a rich Runtime library • You may be familiar with JNA • Foreign Function Interface (FFI) • https://github.com/jnr
  • 60. User Code JNR stub Java JNI call C/native JNI impl libffi Target Library
  • 61. JNR import jnr.ffi.LibraryLoader;! import jnr.ffi.annotations.IgnoreError;!  ! public class GetPidJNRExample {! public interface GetPid {! long getpid();! }! ! public static void main( String[] args ) {! GetPid getpid = LibraryLoader! .create(GetPid.class)! .load("c");! ! getpid.getpid();! }! }
  • 63. jffi Platforms • Darwin (OS X): universal (+ppc?) • Linux: i386, x86_64, arm, ppc, ppc64, s390x • Windows: i386, x86_64 • FreeBSD, OpenBSD: i386, x86_64 • SunOS: i386, x86_64, sparc, sparcv9 • AIX: ppc • OpenVMS, AS/400: builds out there somewhere • If your platform isn't here, contribute a build
  • 64. jnr-ffi • User-oriented API • Roughly equivalent to what JNA gives you • Functions, structs, callbacks, memory • https://github.com/jnr/jnr-ffi
  • 65. jnr-posix • Pre-bound set of POSIX functions • Mostly driven by what JRuby, Jython use • Goal: 100% of POSIX bound to Java
  • 66. public public public public public public public public public public public public public public public public public public public public public public public public public public public public public public public public public public public public public public public public List<? int chmod(String string, int i);! int chown(String string, int i, int i1);! int execv(String string, String[] strings);! int execve(String string, String[] strings, String[] strings1);! int fork();! int seteuid(int i);! int getgid();! String getlogin();! int getpgid();! int getpgid(int i);! int getpgrp();! int getpid();! int getppid();! Passwd getpwent();! Passwd getpwuid(int i);! Passwd getpwnam(String string);! Group getgrgid(int i);! Group getgrnam(String string);! int getuid();! boolean isatty(FileDescriptor fd);! int kill(int i, int i1);! int symlink(String string, String string1);! int link(String string, String string1);! String readlink(String string) throws IOException;! String getenv(String string);! int setenv(String string, String string1, int i);! int unsetenv(String string);! int getpriority(int i, int i1);! int setpriority(int i, int i1, int i2);! int setuid(int i);! FileStat stat(String string);! int stat(String string, FileStat fs);! int umask(int i);! Times times();! int utimes(String string, long[] longs, long[] longs1);! int waitpid(int i, int[] ints, int i1);! int wait(int[] ints);! int errno();! void errno(int i);! int posix_spawnp(String string, List<? extends SpawnFileAction> list, extends CharSequence> list1, List<? extends CharSequence> list2);
  • 67. POSIX posix = POSIXFactory.getPOSIX(! new MyPOSIXHandler(this),! isNativeEnabled);
  • 68. public interface POSIXHandler {! public void error(Errno errno, String string);! public void unimplementedError(String string);! public void warn(WARNING_ID wrngd, String string, Object[] os);! public boolean isVerbose();! public File getCurrentWorkingDirectory();! public String[] getEnv();! public InputStream getInputStream();! public PrintStream getOutputStream();! public int getPID();! public PrintStream getErrorStream();! }
  • 69. public public public public public public public public public int chmod(String string, int i);! int chown(String string, int i, int i1);! int kill(int i, int i1);! int getpriority(int i, int i1);! int setpriority(int i, int i1, int i2);! int waitpid(int i, int[] ints, int i1);! int wait(int[] ints);! int errno();! void errno(int i);
  • 70. jnr-constants • C/preprocessor constants in enum form • Generator code to run on each platform • Several pregenerated sets for jnr-posix
  • 71. public int open(String string, int flags, int mode);! public int socket(int i, int i1);
  • 72. jnr-enxio • Extended Native X-platform IO • NIO-compatible JNR-backed IO library • Read, write, select (kqueue, epoll, etc) • Low-level fcntl control • https://github.com/jnr/jnr-enxio
  • 73. public class NativeSocketChannel! extends AbstractSelectableChannel! implements ByteChannel, NativeSelectableChannel {! public NativeSocketChannel(int fd);! public NativeSocketChannel(int fd, int ops);! public final int validOps();! public final int getFD();! public int read(ByteBuffer dst) throws IOException;! public int write(ByteBuffer src) throws IOException! public void shutdownInput() throws IOException;! public void shutdownOutput() throws IOException;! }
  • 74. jnr-unixsocket • UNIX sockets for NIO • Built atop jnr-enxio • Fully selectable, etc • https://github.com/jnr/jnr-unixsocket
  • 75. What Else? • NIO, NIO.2 • Native IO, symlinks, FS-walking, • Unmanaged memory • Selectable stdio, process IO • Low-level or other sockets (UNIX, ICMP, ...) • New APIs (graphics, crypto, OS, ...)
  • 76. How Does It Perform?
  • 77. Performance • Generated code leading to JNI call • Generated assembly version of native part • jnr-x86asm: Generate and link ASM • Used internally by jnr • https://github.com/jnr/jnr-x86asm
  • 78. JNA getpid JNR getpid getpid calls, 100M times 100000ms 10000ms 1000ms 100ms 10ms 1ms
  • 79. @IgnoreError import jnr.ffi.LibraryLoader;! import jnr.ffi.annotations.IgnoreError;!  ! public class GetPidJNRExample {! public interface GetPid {! @IgnoreError! long getpid();! }! ! public static void main( String[] args ) {! GetPid getpid = LibraryLoader! .create(GetPid.class)! .load("c");! ! getpid.getpid();! }! }
  • 80. JNR getpid JNR getpid @IgnoreError getpid calls, 100M times 2000ms 1500ms 1000ms 500ms 0ms
  • 81. But There's More to Do JNR getpid JNI JNR @IgnoreError getpid calls, 100M times 2000ms 1500ms 1000ms 500ms 0ms GCC -O3
  • 82. JVM Help is Coming • Standard FFI API in JDK • JIT intelligence • Drop JNI overhead where possible • Bind native call directly at call site • Security policies, segv protection, etc • Time for an FFI JSR
  • 84. History • JVM authors mentioned non-Java languages • Language authors have targeted JVM • Hundreds of JVM languages now • But JVM was a mismatch for many of them • Usually required tricks that defeated JVM optimizations • Or required features JDK could not provide
  • 86. Goals of JSR 292 • A user-definable bytecode • Full freedom to define VM behavior • Fast method pointers + adapters • Optimizable like normal Java code • Avoid future modifications
  • 90. Invoke // Static! System.currentTimeMillis()! Math.log(1.0)!  ! // Virtual! "hello".toUpperCase()! System.out.println()!  ! // Interface! myList.add("happy happy")! myRunnable.run()!  ! // Constructor and super! new ArrayList()! super.equals(other)
  • 91. // Static! invokestatic java/lang/System.currentTimeMillis:()J! invokestatic java/lang/Math.log:(D)D! ! // Virtual! invokevirtual java/lang/String.toUpperCase:()Ljava/lang/String;! invokevirtual java/io/PrintStream.println:()V! ! // Interface! invokeinterface java/util/List.add:(Ljava/lang/Object;)Z! invokeinterface java/lang/Runnable.add:()V! ! // Special! invokespecial java/util/ArrayList.<init>:()V! invokespecial java/lang/Object.equals:(java/lang/Object)Z
  • 92. invokevirtual! 1. Confirm object is of correct type 2. Confirm arguments are of correct type 3. Look up method on Java class invokestatic 4. Cache method 5. Invoke method invokestatic! 1. Confirm arguments are of correct type 2. Look up method on Java class 3. Cache method 4. Invoke method invokevirtual invokeinterface! 1. Confirm object’s type implements interface 2. Confirm arguments are of correct type 3. Look up method on Java class invokeinterface 4. Cache method 5. Invoke method invokespecial! 1. Confirm object is of correct type 2. Confirm arguments are of correct type 3. Confirm target method is visible 4. Look up method on Java class 5. Cache method 6. Invoke method invokespecial invokedynamic! 1. Call your bootstrap code 2. Bootstrap wires up a target function 3. Target function invoked directly until you change it
  • 95. Indy Languages • New language impls • JavaScript: Dyn.js and Nashorn • Redline Smalltalk • Improved language performance • JRuby, Groovy, Jython • Java features too!
  • 96. JRuby/Java 6 JRuby/Java 7 Times Faster than Ruby 1.9.3 5 4.32 3.75 3.66 3.44 2.5 2.658 1.914 1.25 0 1.346 base64 1.565 1.538 richards neural redblack
  • 97. red/black tree, pure Ruby versus native ruby-2.0.0 + Ruby 2.48s ruby-2.0.0 + C ext 0.51s jruby + Ruby 0.29s 0 0.75 1.5 Runtime per iteration 2.25 3
  • 98. Caveat Emptor • Indy was really slow in first Java 7 release • Got fast in 7u2...and turned out broken • Rewritten for 7u40 • Slow to warm up • Still some issues (memory use, etc) • Java 8 due in March…
  • 100. JVM Language JVM Bytecode Out of our control Written in C++ Bytecode Interpreter Bytecode JIT Native Code
  • 101. What If… • The JVM’s JIT optimizer were written in Java • You could customize how the JIT works for your language or library • JITed code could directly make native calls
  • 102. Graal • A 100% Java-based JIT framework • Grew out of the 100% Java “Maxine” JVM • Backends to assembly or HotSpot IR • Directly control code generation • Build a language without using JVM bytecode • http://openjdk.java.net/projects/graal/
  • 104. However… • Not everyone is a compiler writer • Graal’s IR is low-level and nontrivial • Need to understand JVM internals • Need some understanding of CPU
  • 105. The Dream • Design your language • ??? • PROFIT
  • 106. What We Want • Design your language • Write an interpreter • PROFIT
  • 107. Truffle • Language framework built on Graal • Designed to fulfill the dream • Implement interpreter • Truffle feeds that to backend • No compiler expertise needed • https://wiki.openjdk.java.net/display/Graal/Truffle+FAQ+and+Guidelines
  • 111. What Have We Learned?
  • 112. The JVM has its problems, but we can fix them.
  • 113. OpenJDK and all these solutions are really, truly, open source.
  • 115. Thank you! • Charles Oliver Nutter • @headius, headius@headius.com • http://blog.headius.com