Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

HotSpot ● The brain in which our Java and Scala juices flow. ● Its execution speed and efficiency is nearing that of native compiled code. ● At its core: The JIT compiler.

Slide 3

Slide 3 text

So... The JIT compiler? ● Information is gathered at runtime. ○ Which paths in the code are traveled often? ○ Which methods are called the most, or, where are the hot spots?

Slide 4

Slide 4 text

So... The JIT compiler? ● Once enough information about a hot method is collected... ○ The compiler kicks in. ○ Compiles the bytecode into a lean and efficient native version of itself. ○ May re-compile later due to over-optimism.

Slide 5

Slide 5 text

Some standard optimizations ● Simple method inlining. ● Dead code removal. ● Native math ops instead of library calls. ● Invariant hoisting.

Slide 6

Slide 6 text

Some are extra awesome!

Slide 7

Slide 7 text

Divide and conquer How many times have you used the following pattern? StringBuilder sb = new StringBuilder("Ingredients: "); for (int i = 0; i < ingredients.length; i++) { if (i > 0) { sb.append(", "); } sb.append(ingredients[i]); } return sb.toString();

Slide 8

Slide 8 text

Divide and conquer ...or perhaps this one? boolean nemoFound = false; for (int i = 0; i < fish.length; i++) { String curFish = fish[i]; if (!nemoFound) { if (curFish.equals("Nemo")) { System.out.println("Nemo! There you are!"); nemoFound = true; continue; } } if (nemoFound) { System.out.println("We already found Nemo!"); } else { System.out.println("We still haven't found Nemo :("); } }

Slide 9

Slide 9 text

Divide and conquer ● Both loops do one thing for a while, ● Then another thing from a certain point on. ● The compiler can spot these patterns. ○ Split the loops into cases. ○ “Peel” several iterations.

Slide 10

Slide 10 text

Divide and conquer ● The condition: if (i > 0) ○ false once, ○ true thereafter. ○ Peel one iteration! StringBuilder sb = new StringBuilder("Ingredients: "); for (int i = 0; i < ingredients.length; i++) { if (i > 0) { sb.append(", "); } sb.append(ingredients[i]); } return sb.toString();

Slide 11

Slide 11 text

Divide and conquer ...will compile as if it were written like so: StringBuilder sb = new StringBuilder("Ingredients: "); if (ingredients.length > 0) { sb.append(ingredients[0]); for (int i = 1; i < ingredients.length; i++) { sb.append(", "); sb.append(ingredients[i]); } } return sb.toString(); First iteration All other iterations

Slide 12

Slide 12 text

Living on the edge ● Null checks are bread-and-butter. ● Sometimes null is a valid value: ○ Missing values ○ Error indication ● Sometimes we check just to be on the safe side.

Slide 13

Slide 13 text

Living on the edge Some checks may be practically redundant. If your code behaves well, the assertion may never fail. public static String l33tify(String phrase) { if (phrase == null) { throw new IllegalArgumentException("Null bad!"); } return phrase.replace('e', '3'); }

Slide 14

Slide 14 text

Living on the edge ● Code runs many, many times. ● The assertion never fails. ● The JIT compiler is optimistic. ...assumes the check is unnecessary!

Slide 15

Slide 15 text

Living on the edge The compiler may drop the check altogether, and compile it as if it were written like so: public static String l33tify(String phrase) { if (phrase == null) { throw new IllegalArgumentException("Null bad!"); } return phrase.replace('e', '3'); }

Slide 16

Slide 16 text

Living on the edge Wait... What if that happy-path assumption eventually proves to be wrong?

Slide 17

Slide 17 text

Living on the edge ● The JVM is now executing native code. ○ A null reference would not result in a fuzzy NullPointerException. ...but rather in a real, harsh memory access violation.

Slide 18

Slide 18 text

Living on the edge ● The JVM intercepts the SIGSEGV (and recovers) ● Follows-up with a de-optimization. ...Method is recompiled, this time with the null check in place.

Slide 19

Slide 19 text

Virtual insanity The JIT compiler has dynamic runtime data on which it can rely when making decisions.

Slide 20

Slide 20 text

Virtual insanity Method inlining: Step 1: Take invoked method. Step 2: Take invoker method. Step 3: Embed former in latter.

Slide 21

Slide 21 text

Virtual insanity Method inlining: ○ Useful when trying to avoid costly invocations. ○ Tricky when dealing with dynamic dispatch.

Slide 22

Slide 22 text

Virtual insanity public class Main { public static void perform(Song s) { s.sing(); } } public interface Song { public void sing(); }

Slide 23

Slide 23 text

Virtual insanity public class GangnamStyle implements Song { @Override public void sing() { println("Oppan gangnam style!"); } } public class Baby implements Song { @Override public void sing() { println("And I was like baby, baby, baby, oh"); } } public class BohemianRhapsody implements Song { @Override public void sing() { println("Thunderbolt and lightning, very very frightening me"); } }

Slide 24

Slide 24 text

Virtual insanity ● perform might run millions of times. ● Each time, sing is invoked. This is a co$tly dynamic dispatch!

Slide 25

Slide 25 text

Virtual insanity Inlining polymorphic calls is not so simple... ...in a static compiler.

Slide 26

Slide 26 text

Virtual insanity The JIT compiler is dynamic. Take advantage of runtime information!

Slide 27

Slide 27 text

Virtual insanity The JVM might decide, according to the statistics it gathered, that 95% of the invocations target an instance of GangnamStyle.

Slide 28

Slide 28 text

Virtual insanity The compiler can perform an optimistic optimization: Eliminate the virtual calls to sing. ...or most of them anyway.

Slide 29

Slide 29 text

Virtual insanity Optimized compiled code will behave like so: public static void perform(Song s) { if (s fastnativeinstanceof GangnamStyle) { println("Oppan gangnam style!"); } else { s.sing(); } }

Slide 30

Slide 30 text

Can I help? ● The JIT compiler is built to optimize: ○ Straightforward, simple code. ○ Common patterns. ○ No nonsense.

Slide 31

Slide 31 text

Can I help? The best way to help your compiler is to not try so hard to help it. Just write your code as you otherwise would!

Slide 32

Slide 32 text

No content