<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.0.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2020-06-12T11:13:08-05:00</updated><id>/feed.xml</id><title type="html">Martijn Dwars</title><subtitle>A blog on programming, profiling, Java, JVM, and anything related to programming languages.</subtitle><entry><title type="html">Graal vs. C2: Battle of the JITs</title><link href="/2020/02/24/graal-vs-c2.html" rel="alternate" type="text/html" title="Graal vs. C2: Battle of the JITs" /><published>2020-02-24T03:50:38-06:00</published><updated>2020-02-24T03:50:38-06:00</updated><id>/2020/02/24/graal-vs-c2</id><content type="html" xml:base="/2020/02/24/graal-vs-c2.html">&lt;p&gt;&lt;a href=&quot;https://www.graalvm.org&quot;&gt;GraalVM&lt;/a&gt; claims to “&lt;em&gt;Run Programs Faster Anywhere 🚀&lt;/em&gt;”.
Indeed, existing applications often run faster on GraalVM compared to OpenJDK and Oracle JDK.
For example, &lt;a href=&quot;https://www.youtube.com/watch?v=PtgKmzgIh4c&quot;&gt;Twitter&lt;/a&gt; reports 11 percent reduction in CPU utilization by using Graal CE.
With GraalVM EE they were even able to reduce CPU utilization by a staggering 20 percent.
What often remains undiscussed, however, is &lt;em&gt;how&lt;/em&gt; GraalVM exactly achieves this performance speedup.
In this blog post I try to answer this question by comparing GraalVM EE 20.0.0 to Oracle Java 8u241 on a number of benchmarks.&lt;/p&gt;

&lt;p&gt;This post is an extended version of the talk I gave at the Compiler Construction course (&lt;a href=&quot;https://tudelft-cs4200-2019.github.io/&quot;&gt;CS4200&lt;/a&gt;) at Delft University of Technology, the slides of which are available &lt;a href=&quot;https://labs.oracle.com/pls/apex/f?p=94065:40150:0::::P40150_PUBLICATION_ID:6110&quot;&gt;here&lt;/a&gt;.
Both my talk and this post are inspired by Ionut Balosin’s &lt;a href=&quot;https://www.youtube.com/watch?v=lunJmMBkqLo&quot;&gt;A race of two compilers&lt;/a&gt;.
I have also taken a lot of inspiration from Aleksey Shipilev’s &lt;a href=&quot;https://shipilev.net/jvm/anatomy-quarks/&quot;&gt;JVM Anatomy Quarks&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Before discussing how GraalVM achieves a performance speedup over Oracle JDK, we need to briefly introduce the JVM’s tiered compilation scheme.
The first step to run a Java program is to compile a &lt;code class=&quot;highlighter-rouge&quot;&gt;.java&lt;/code&gt; file containing Java source to a &lt;code class=&quot;highlighter-rouge&quot;&gt;.class&lt;/code&gt; file containing JVM bytecode.
When running the resulting &lt;code class=&quot;highlighter-rouge&quot;&gt;.class&lt;/code&gt; file, the JVM goes through several stages:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;First the bytecode is &lt;em&gt;interpreted&lt;/em&gt;. You can think of this as a loop that processes each bytecode instruction individually, altering the state of the virtual machine according to the semantics of the instruction.&lt;/li&gt;
  &lt;li&gt;Once a method becomes &lt;em&gt;hot&lt;/em&gt; the client compiler (C1) compiles the bytecode to machine code (instructions native to the host platform) that carries out equivalent operations. C1 is a fast, lightly optimizing bytecode compiler.&lt;/li&gt;
  &lt;li&gt;When the code becomes even hotter, the server compiler (C2) kicks in. This compiler produces the most performant machine code.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;well&quot;&gt;
  &lt;p&gt;&lt;strong&gt;A note on JIT&lt;/strong&gt;
A bytecode interpreter is much slower than the equivalent machine code, often by at least an order of magnitude.
What is the great thing about JIT compilation then?
First, while the bytecode is being interpreted the profiler collects information such as how often a branch is taken and what types of values are being observed.
The JIT compiler can include this profiling information when deciding what machine code to generate.
Second, and more importantly, the JIT compiler can make &lt;em&gt;speculative assumptions&lt;/em&gt; and &lt;em&gt;deoptimize&lt;/em&gt; if these assumptions turn out to be wrong.
These two ingredients make it possible for a JIT compiler to outperform an ahead-of-time compiler.&lt;/p&gt;
&lt;/div&gt;

&lt;!-- TODO: I want to add an example on how to have java print the compilation results. I think this &quot;tutorial&quot; style is a distinguishing factor for my blog --&gt;

&lt;p&gt;For the purpose of this blog post it is important to know that in GraalVM the C1 and C2 JIT compilers have been replaced by the Graal JIT compiler.
The next four sections each present an experiment in which GraalVM is compared to Oracle Java.
The code for the benchmarks in this blog post is available on &lt;a href=&quot;https://github.com/MartijnDwars/battle-of-the-jits&quot;&gt;GitHub&lt;/a&gt;.
The benchmarks are run GraalVM EE 20.0.0 or Oracle Java 8u241 on a MacBook Pro (13-inch, 2017, 2.5 GHz Intel Core i7).&lt;/p&gt;

&lt;h2 id=&quot;partial-escape-analysis&quot;&gt;(Partial) Escape Analysis&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Escape_analysis&quot;&gt;Escape analysis&lt;/a&gt; is a method for determining the dynamic scope of pointers.
Essentially, escape analysis tells us when a reference to an object can &lt;em&gt;escape&lt;/em&gt; to other threads of execution or to calling subroutines.
A couple of interesting optimizations can be performed when an object is known NOT to escape:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;em&gt;Stack allocation&lt;/em&gt;. With stack allocation, an object is allocated on the stack instead of the heap. Stack allocation is much faster than heap allocation, because it only involves moving the stack pointer. In addition, stack allocation avoids the need for expensive garbage collection.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Scalar replacement&lt;/em&gt;. &lt;a href=&quot;https://shipilev.net/jvm/anatomy-quarks/18-scalar-replacement/&quot;&gt;Scalar replacement&lt;/a&gt; replaces an object by its fields. Like with stack allocation, the fields may be allocated on the stack instead of the heap. In addition, the scalar variables may be amenable to further optimizations.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Lock coarsening&lt;/em&gt;. With lock coarsening, the expensive locking operation is eliminated. Some classes in the Java standard library assume that a class may be used in a multithreaded environment, so they pessimistically synchronized access to those methods. However, if an object never leaves the method in which it is constructed, no two threads will ever access this object, and methods that access this object do not need to be synchronized.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Partial&lt;/em&gt; escape analysis is a stronger variant of escape analysis that determines whether an object escapes on each path through a method instead of the method as a whole.
This means that even if there is a path through the method in which the object escapes, we may still be able to apply above optimizations on the other paths.
Of course, nothing comes for free: the compiler needs to insert instructions to reconstruct the object on the heap when the “escaping” path is taken. Let’s look at an example.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;nd&quot;&gt;@Warmup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Measurement&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Fork&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@BenchmarkMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Mode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;AverageTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@OutputTimeUnit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;TimeUnit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;NANOSECONDS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@State&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Benchmark&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ScalarReplacement&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nd&quot;&gt;@Setup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Iteration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;shake&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ThreadLocalRandom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nextBoolean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nd&quot;&gt;@Benchmark&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Blackhole&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blackhole&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nc&quot;&gt;MyObject&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyObject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyObject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;blackhole&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;consume&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyObject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MyObject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Benchmark&lt;/th&gt;
      &lt;th&gt;Dist&lt;/th&gt;
      &lt;th&gt;Mode&lt;/th&gt;
      &lt;th&gt;Cnt&lt;/th&gt;
      &lt;th&gt;Score ±   Error&lt;/th&gt;
      &lt;th&gt;Units&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Escape.split&lt;/td&gt;
      &lt;td&gt;graal&lt;/td&gt;
      &lt;td&gt;avgt&lt;/td&gt;
      &lt;td&gt;5&lt;/td&gt;
      &lt;td&gt;669.760 ±  78.310&lt;/td&gt;
      &lt;td&gt;ns/op&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Escape.split&lt;/td&gt;
      &lt;td&gt;oracle&lt;/td&gt;
      &lt;td&gt;avgt&lt;/td&gt;
      &lt;td&gt;5&lt;/td&gt;
      &lt;td&gt;1182.732 ± 145.990&lt;/td&gt;
      &lt;td&gt;ns/op&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The benchmark shows that Graal is about twice as fast as C2.
Let’s add the &lt;code class=&quot;highlighter-rouge&quot;&gt;perfasm&lt;/code&gt; (&lt;code class=&quot;highlighter-rouge&quot;&gt;dtraceasm&lt;/code&gt;) profiler to take a look at the assembly code that gets generated:&lt;/p&gt;

&lt;p&gt;Graal:&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  0.12%  ↗  0x000000011c191640: mov    %r11d,0x2c(%rsp)
  9.17%  │  0x000000011c191645: mov    0xc(%r10),%r9d     ; *getfield x
  1.69%  │  0x000000011c191649: mov    %rdi,%rsi          ; *invokevirtual consume
  0.23%  │  0x000000011c19164c: mov    %r9d,%edx
  0.07%  │  0x000000011c19164f: callq  0x000000011bf990a0 ; *invokevirtual consume
 16.97%  │  0x000000011c191654: nop
  1.55%  │  0x000000011c191655: mov    0x2c(%rsp),%r11d
  0.33%  │  0x000000011c19165a: inc    %r11d              ; *iinc
  8.39%  │  0x000000011c19165d: mov    0x8(%rsp),%r10
  1.76%  │  0x000000011c191662: mov    0x10(%rsp),%rdi    ; *iload_2
  0.09%  │  0x000000011c191667: cmp    $0x12c,%r11d
         ╰  0x000000011c19166e: jl     0x000000011c191640 ; *if_icmpge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see, there is no trace of the &lt;code class=&quot;highlighter-rouge&quot;&gt;MyObject&lt;/code&gt; construction.
Instead, the field &lt;code class=&quot;highlighter-rouge&quot;&gt;x&lt;/code&gt; is immediately passed to the &lt;code class=&quot;highlighter-rouge&quot;&gt;consume&lt;/code&gt; function.
Lets look at what happens on Oracle Java:&lt;/p&gt;

&lt;p&gt;Oracle:&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  0.12%  ↗  0x000000011e7a44bf: mov    0x50(%rsp),%r9
  0.12%  │  0x000000011e7a44c4: movzbl 0x94(%r9),%r10d        ; *getfield isDone
  0.12%  │  0x000000011e7a44cc: mov    0x8(%rsp),%rbx
         │  0x000000011e7a44d1: add    $0x1,%rbx              ; *ifeq
         │  0x000000011e7a44d5: test   %eax,-0xf8ae4db(%rip)
         │  0x000000011e7a44db: test   %r10d,%r10d
         │  0x000000011e7a44de: jne    0x000000011e7a469b     ; *aload
  0.02%  │  0x000000011e7a44e4: xor    %ebp,%ebp
         │  0x000000011e7a44e6: jmp    0x000000011e7a4558
         │  0x000000011e7a44e8: nopl   0x0(%rax,%rax,1)
  0.82%  │  0x000000011e7a44f0: mov    %r10,0x60(%r15)
  0.32%  │  0x000000011e7a44f4: prefetchw 0xc0(%r10)
  3.30%  │  0x000000011e7a44fc: mov    0x18(%rsp),%r11
  1.05%  │  0x000000011e7a4501: mov    0xa8(%r11),%r10
  0.82%  │  0x000000011e7a4508: mov    %r10,(%rax)
  1.57%  │  0x000000011e7a450b: movl   $0xf80190ff,0x8(%rax)  ; Put class word header
  3.32%  │  0x000000011e7a4512: mov    %r12d,0xc(%rax)        ; *new
  1.80%  │  0x000000011e7a4516: mov    0x24(%rsp),%r10d
  0.90%  │  0x000000011e7a451b: mov    %r10d,0xc(%rax)        ; *synchronization entry
  1.22%  │  0x000000011e7a451f: mov    %r8,(%rsp)
  1.80%  │  0x000000011e7a4523: mov    %r9,0x50(%rsp)
  1.92%  │  0x000000011e7a4528: mov    %r11,0x18(%rsp)
  0.47%  │  0x000000011e7a452d: mov    %rbx,0x8(%rsp)         ; *aload_1
  1.47%  │  0x000000011e7a4532: mov    0xc(%rax),%edx         ; *getfield x
  5.20%  │  0x000000011e7a4535: mov    0x60(%rsp),%rsi
  1.62%  │  0x000000011e7a453a: nop
  0.47%  │  0x000000011e7a453b: callq  0x000000011e5e00a0     ; *invokevirtual consume
 10.67%  │  0x000000011e7a4540: inc    %ebp                   ; *iinc
  1.80%  │  0x000000011e7a4542: cmp    $0x12c,%ebp
         ╰  0x000000011e7a4548: jge    0x000000011e7a44bf     ; *if_icmpge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the introduction I mentioned that Twitter is able to achieve 11 percent reduction in CPU utilization by switching to the Graal JIT-compiler.
They also report that using Graal without partial escape analysis results in 5 percent reduction in CPU utilization.
This should give you an idea of how big the contribution of escape analysis is to Graal’s performance.
If you want to learn more about escape analysis I can recommend Lukas Stadler’s &lt;a href=&quot;http://ssw.jku.at/Teaching/PhDTheses/Stadler/index.html&quot;&gt;PhD thesis&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;data-flow-analysis&quot;&gt;Data-Flow Analysis&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Data-flow_analysis&quot;&gt;Data-flow analysis&lt;/a&gt; is a technique for gathering information about the possible set of values calculated at various points in a computer program.
One example of data-flow analysis is &lt;a href=&quot;https://en.wikipedia.org/wiki/Constant_folding&quot;&gt;constanat folding&lt;/a&gt;: the process of recognizing and evaluating constant expressions at compile time rather than computing them at runtime.
Constant folding can make use of arithmetic identities, e.g. if &lt;code class=&quot;highlighter-rouge&quot;&gt;x&lt;/code&gt; is an integer, then the value &lt;code class=&quot;highlighter-rouge&quot;&gt;0 * x&lt;/code&gt; is zero independent of the value of &lt;code class=&quot;highlighter-rouge&quot;&gt;x&lt;/code&gt;.
This is a fairly obvious example, but what follows is an example of constant folding that may not be so obvious.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;nd&quot;&gt;@Warmup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeUnit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SECONDS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Measurement&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeUnit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SECONDS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Fork&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@BenchmarkMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Mode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;AverageTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@OutputTimeUnit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;TimeUnit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;NANOSECONDS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@State&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Benchmark&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Dataflow&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nd&quot;&gt;@Benchmark&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;simpleRandom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Random&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Random&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nextInt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Random values are always in [0, 1]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// This is always false&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we run this on GraalVM EE 20.0.0 and Oracle Java we get the following result:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Benchmark&lt;/th&gt;
      &lt;th&gt;Dist&lt;/th&gt;
      &lt;th&gt;Mode&lt;/th&gt;
      &lt;th&gt;Cnt&lt;/th&gt;
      &lt;th&gt;Score&lt;/th&gt;
      &lt;th&gt;Units&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Dataflow.random&lt;/td&gt;
      &lt;td&gt;graal&lt;/td&gt;
      &lt;td&gt;avgt&lt;/td&gt;
      &lt;td&gt;10&lt;/td&gt;
      &lt;td&gt;51.730 ±   4.008&lt;/td&gt;
      &lt;td&gt;ns/op&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Dataflow.random&lt;/td&gt;
      &lt;td&gt;oracle&lt;/td&gt;
      &lt;td&gt;avgt&lt;/td&gt;
      &lt;td&gt;10&lt;/td&gt;
      &lt;td&gt;2481.222 ± 107.754&lt;/td&gt;
      &lt;td&gt;ns/op&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;It appears that Graal’s data-flow analysis could deduce that &lt;code class=&quot;highlighter-rouge&quot;&gt;r &amp;gt; 1&lt;/code&gt;.
Let’s look at the implementation of &lt;code class=&quot;highlighter-rouge&quot;&gt;Random#nextInt(int)&lt;/code&gt; and speculate what may happen under the hoods:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Random&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;nextInt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bound&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bound&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bound&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bound&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// Omitted for brevity&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The parameter &lt;code class=&quot;highlighter-rouge&quot;&gt;bound&lt;/code&gt; will be bound to &lt;code class=&quot;highlighter-rouge&quot;&gt;2&lt;/code&gt;, which means the method will return &lt;code class=&quot;highlighter-rouge&quot;&gt;(int) ((bound * (long) r) &amp;gt;&amp;gt; 31)&lt;/code&gt;.
Without making any assumption about the value of &lt;code class=&quot;highlighter-rouge&quot;&gt;r&lt;/code&gt;, what are the possible values of this expression?
Let’s introduce some notation to make the discussion easier: each bit is either &lt;code class=&quot;highlighter-rouge&quot;&gt;0&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;1&lt;/code&gt;, or &lt;code class=&quot;highlighter-rouge&quot;&gt;x&lt;/code&gt; (unknown), and &lt;code class=&quot;highlighter-rouge&quot;&gt;b{n}&lt;/code&gt; denotes the repetition of &lt;code class=&quot;highlighter-rouge&quot;&gt;n&lt;/code&gt; times &lt;code class=&quot;highlighter-rouge&quot;&gt;b&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;We start with 32 bits: &lt;code class=&quot;highlighter-rouge&quot;&gt;1x{31}&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;0x{31}&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Widen (sign-extend) to 64 bits: &lt;code class=&quot;highlighter-rouge&quot;&gt;1{32}1x{31}&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;0{32}0x{31}&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Shift one position left: &lt;code class=&quot;highlighter-rouge&quot;&gt;1{31}1x{31}0&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;0{31}0x{31}0&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Shift 31 positions right: &lt;code class=&quot;highlighter-rouge&quot;&gt;1{31}1{31}1x&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;0{31}0{31}0x&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Narrow to 32 bits: &lt;code class=&quot;highlighter-rouge&quot;&gt;1{31}x&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;0{31}x&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Without knowing anything about the random value &lt;code class=&quot;highlighter-rouge&quot;&gt;r&lt;/code&gt; we know that this expression evaluates to one of at most four possible values:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;1{31}0&lt;/code&gt; or -2&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;1{32}&lt;/code&gt; or -1&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;0{32}&lt;/code&gt; or 0&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;0{31}1&lt;/code&gt; or 1&lt;/li&gt;
&lt;/ul&gt;

&lt;!--
Given these possible outcomes, it is not hard to see that `r &gt; 1` is never true.
Indeed, if we re-run the JMH benchmark with `-prof perfasm`, we see that Graal omits the full benchmark:

```
TODO
```
--&gt;

&lt;p&gt;This example may seem a bit contrived: nobody would every write &lt;code class=&quot;highlighter-rouge&quot;&gt;random.nextInt(2) &amp;gt; 1&lt;/code&gt;.
However, it illustrates the surprising ways in which Graal is able to optimize our code.
Moreover, this example shows that if the JIT compiler knows that the range of possible values is restricted to some subset, it may be able to perform more aggressive optimizations and generate more efficient code.&lt;/p&gt;

&lt;h2 id=&quot;inlining&quot;&gt;Inlining&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Inline_expansion&quot;&gt;Inlining&lt;/a&gt; is a compiler optimization that replaces a function call site with the body of the called function.
It is &lt;a href=&quot;https://medium.com/graalvm/under-the-hood-of-graalvm-jit-optimizations-d6e931394797&quot;&gt;one of the fundamental&lt;/a&gt; optimizations because it creates new opportunities for optimization.
The Graal inliner is much more aggressive; the following example shows why.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;nd&quot;&gt;@Warmup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeUnit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SECONDS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Measurement&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeUnit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SECONDS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Fork&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@BenchmarkMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Mode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;AverageTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@OutputTimeUnit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;TimeUnit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;NANOSECONDS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@State&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Benchmark&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Inlining&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;C1&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;C2&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;C3&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nd&quot;&gt;@Setup&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* fill as with c1, c2, c3, c1, c2, ... */&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;C1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;C2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;C3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nd&quot;&gt;@Benchmark&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We have defined a class &lt;code class=&quot;highlighter-rouge&quot;&gt;A&lt;/code&gt; with an abstract method &lt;code class=&quot;highlighter-rouge&quot;&gt;m&lt;/code&gt; and three concrete subclasses &lt;code class=&quot;highlighter-rouge&quot;&gt;C1&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;C2&lt;/code&gt;, and &lt;code class=&quot;highlighter-rouge&quot;&gt;C3&lt;/code&gt; that implement &lt;code class=&quot;highlighter-rouge&quot;&gt;m&lt;/code&gt;.
The arary &lt;code class=&quot;highlighter-rouge&quot;&gt;as&lt;/code&gt; is filled with instances of &lt;code class=&quot;highlighter-rouge&quot;&gt;C1&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;C2&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;C3&lt;/code&gt; in a round-robin fashion.
The benchmark invokes the method &lt;code class=&quot;highlighter-rouge&quot;&gt;m&lt;/code&gt; on each item &lt;code class=&quot;highlighter-rouge&quot;&gt;a&lt;/code&gt; in the array &lt;code class=&quot;highlighter-rouge&quot;&gt;as&lt;/code&gt;.
Since this is a &lt;em&gt;virtual method call&lt;/em&gt;, the runtime needs to resolve the implementation based on the runtime type of the receiver &lt;code class=&quot;highlighter-rouge&quot;&gt;a&lt;/code&gt;.
Lets look at how the two JITs perform on this example:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Dist&lt;/th&gt;
      &lt;th&gt;Benchmark&lt;/th&gt;
      &lt;th&gt;Mode&lt;/th&gt;
      &lt;th&gt;Cnt&lt;/th&gt;
      &lt;th&gt;Score    Error&lt;/th&gt;
      &lt;th&gt;Units&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Oracle&lt;/td&gt;
      &lt;td&gt;Inlining.test&lt;/td&gt;
      &lt;td&gt;avgt&lt;/td&gt;
      &lt;td&gt;10&lt;/td&gt;
      &lt;td&gt;769.603 ± 24.531&lt;/td&gt;
      &lt;td&gt;ns/op&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Graal&lt;/td&gt;
      &lt;td&gt;Inlining.test&lt;/td&gt;
      &lt;td&gt;avgt&lt;/td&gt;
      &lt;td&gt;10&lt;/td&gt;
      &lt;td&gt;497.817 ± 13.365&lt;/td&gt;
      &lt;td&gt;ns/op&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Graal is much faster (1.55x) than Oracle.
Lets look at the assembly code to see what is going on (by adding &lt;code class=&quot;highlighter-rouge&quot;&gt;-prof perafsm&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;-prof dtraceasm&lt;/code&gt; to the JMH command):&lt;/p&gt;

&lt;p&gt;Oracle:&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Oracle:
  9.75%  ↗  0x54790: mov    0x40(%rsp),%r9
  0.14%  │  0x54795: data16 data16 nopw 0x0(%rax,%rax,1) ; *aload_1
  0.88%  │  0x547a0: mov    0x10(%r9,%rbp,4),%r10d
  8.10%  │  0x547a5: mov    %r9,0x40(%rsp)
  1.52%  │  0x547aa: mov    %r10,%rsi
  0.06%  │  0x547ad: shl    $0x3,%rsi
  0.94%  │  0x547b1: movabs $0xffffffffffffffff,%rax
  8.19%  │  0x547bb: callq  0x032e0            ; *invokevirtual m
  1.24%  │  0x547c0: inc    %ebp               ; *iinc
  0.85%  │  0x547c2: cmp    0x10(%rsp),%ebp
         ╰  0x547c6: jl     0x54790

C1::m
  &amp;lt;function prologue&amp;gt;
  0.55%    0x53b0c: incl   0xc(%rsi)  ; Increment at offset 12 (= field c1)
  &amp;lt;function epilogue&amp;gt;

C2::m
  &amp;lt;function prologue&amp;gt;
  0.50%    0x538cc: incl   0x10(%rsi) ; Increment at offset 16 (= field c2)
  &amp;lt;function epilogue&amp;gt;

C3::m
  &amp;lt;function prologue&amp;gt;
  0.36%    0x5368c: incl   0x14(%rsi) ; Increment at offset 20 (= field c3)
  &amp;lt;function epilogue&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Graal:&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  2.81%      │││  0x1d89: mov    0x10(%r8,%rcx,4),%ebx     ; *aaload
  9.85%      │││  0x1d8e: mov    %ecx,%edi
  2.67%      │││  0x1d90: inc    %edi                      ; *iinc
  3.56%      │││  0x1d9a: cmpl   $0xf801e2c3,0x8(,%rbx,8)  ; {metadata(&quot;C2&quot;)} | Is this object of class C2?
 24.41%   ╭  │││  0x1da5: je     0x1e0e                                       | If yes, jump to inlined C2::m
  0.70%   │  │││  0x1db3: cmpl   $0xf801e341,0x8(,%rbx,8)  ; {metadata(&quot;C3&quot;)} | Is this object of class C3?
  5.15%   │ ╭│││  0x1dbe: jne    0x1de3                    ; *invokevirtual m | If no, jump over C3::m to next check
  2.04%   │ ││││  0x1dc4: mov    $0x1,%ecx                                    | Inlined C3::m
  0.15%   │ ││││  0x1dc9: add    0x14(,%rbx,8),%ecx        ; *iadd            | Inlined C3::m
  3.41%   │ ││││  0x1dd0: mov    %ecx,0x14(,%rbx,8)        ; *putfield c3     | Inlined C3::m
  2.78%   │ ││││  0x1dd7: mov    %edi,%ecx
  0.22%   │ │╰││  0x1dd9: jmp    0x1d80                                       | Jump back to process next object
  3.56%   │ ↘ ││  0x1de3: cmpl   $0xf801e302,0x8(,%rbx,8)  ; {metadata(&quot;C1&quot;)} | Is this object of class C1?
  2.07%   │   ││  0x1dee: jne    0x1eb2                    ; *invokevirtual m | If not, jump to virtual call
  3.52%   │   ││  0x1df4: mov    $0x1,%ecx                                    | Inlined C1::m
  0.63%   │   ││  0x1df9: add    0xc(,%rbx,8),%ecx         ; *iadd            | Inlined C1::m
  1.15%   │   ││  0x1e00: mov    %ecx,0xc(,%rbx,8)         ; *putfield c1     | Inlined C1::m
  4.44%   │   ││  0x1e07: mov    %edi,%ecx
  2.07%   │   ╰│  0x1e09: jmpq   0x1d80                    ; *invokevirtual m | Jump back to process next object
  5.00%   ↘    │  0x1e0e: mov    $0x1,%ecx                                    | Inlined C2::m
  0.33%        │  0x1e13: add    0x10(,%rbx,8),%ecx        ; *iadd            | Inlined C2::m
  0.81%        │  0x1e1a: mov    %ecx,0x10(,%rbx,8)        ; *putfield c2     | Inlined C2::m
  7.11%        │  0x1e21: mov    %edi,%ecx
  0.52%        ╰  0x1e23: jmpq   0x1d80                    ; *iload_3         | Jump back to process next object
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Oracle did not inline the method call.
Instead, the JVM function invocation translates to an assembly call, including the necessary function prologue/epilogue.
Graal, on the other hand, compares the object’s &lt;em&gt;class word&lt;/em&gt; against the native pointer of the VMs Klass instance to decide which implementation to use, and jumps to that implementation.
Only when an instance that is not of class C1, C2, C3 is observed does the code fall back to a virtual call.&lt;/p&gt;

&lt;div class=&quot;well&quot;&gt;
  &lt;p&gt;&lt;strong&gt;Influencing the Inliner&lt;/strong&gt;
We’ve looked at how megamorphic call sites are inlined in C2 and Graal, but there are many other factors that may influence the inliner.
For example, in C2 you can specify the maximum number of nested calls that are inlined (&lt;code class=&quot;highlighter-rouge&quot;&gt;-XX:MaxInlineLevel&lt;/code&gt;) and a maximum bytecode size of a method to be inlined (&lt;code class=&quot;highlighter-rouge&quot;&gt;-XX:MaxInlineSize&lt;/code&gt;).&lt;/p&gt;
&lt;/div&gt;

&lt;h2 id=&quot;vectorization&quot;&gt;Vectorization&lt;/h2&gt;

&lt;p&gt;Modern processors support instructions that perform the same operation on multiple data points simultaneously.
Such instructions are known as &lt;em&gt;single instruction, multiple data&lt;/em&gt; (SIMD).
Java does not yet support Vector intrinsics (&lt;a href=&quot;https://openjdk.java.net/jeps/338&quot;&gt;JEP 338&lt;/a&gt;), so to benefit from SIMD instructions the JIT compiler has to apply &lt;em&gt;autovectorization&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;One example where vectorization can help is UTF-8 to UTF-16 decoding.
In UTF-8 each character occupies 1-4 bytes, whereas in UTF-16 each character occupies exactly 2 bytes.
If the string in question only contains ASCII characters, then the decoding is just a widening conversion of each byte.
With SIMD instructions this widening conversion can be performed for multiple bytes in parallel.
The following code shows how such a fast-path decoding could look like.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;nd&quot;&gt;@Benchmark&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Warmup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeUnit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SECONDS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Measurement&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeUnit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SECONDS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Fork&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@BenchmarkMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Mode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;AverageTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@OutputTimeUnit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;TimeUnit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;NANOSECONDS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@State&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Benchmark&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Vectorization&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nd&quot;&gt;@Setup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Iteration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2048&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Random&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Random&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2048&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nextInt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;65&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;decodeAscii&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Blackhole&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blackhole&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2048&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;decodeGeneric&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nd&quot;&gt;@CompilerControl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;DONT_INLINE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;decodeGeneric&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we run this benchmark we obtain the following results:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Benchmark&lt;/th&gt;
      &lt;th&gt;Compiler&lt;/th&gt;
      &lt;th&gt;Mode&lt;/th&gt;
      &lt;th&gt;Cnt&lt;/th&gt;
      &lt;th&gt;Score ± Error&lt;/th&gt;
      &lt;th&gt;Units&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Vectorization.decodeAscii&lt;/td&gt;
      &lt;td&gt;C2&lt;/td&gt;
      &lt;td&gt;avgt&lt;/td&gt;
      &lt;td&gt;10&lt;/td&gt;
      &lt;td&gt;547.945 ± 5.376&lt;/td&gt;
      &lt;td&gt;ns/op&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Vectorization.decodeAscii&lt;/td&gt;
      &lt;td&gt;Graal&lt;/td&gt;
      &lt;td&gt;avgt&lt;/td&gt;
      &lt;td&gt;10&lt;/td&gt;
      &lt;td&gt;147.822 ± 5.606&lt;/td&gt;
      &lt;td&gt;ns/op&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Graal outperforms C2 by 3.7x, that is a pretty big difference!
Lets add &lt;code class=&quot;highlighter-rouge&quot;&gt;-prof dtraceasm&lt;/code&gt; (Linux: &lt;code class=&quot;highlighter-rouge&quot;&gt;-prof perfasm&lt;/code&gt;) and take a look at the assembly code that the two JIT compilers generate.&lt;/p&gt;

&lt;h4 id=&quot;c2&quot;&gt;C2&lt;/h4&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	0x08: mov    $0x200,%ecx
	0x0d: xor    %rax,%rax
	0x10: shl    $0x3,%rcx
	0x14: rep rex.W stos %al,%es:(%rdi)
	0x17: prefetchw 0x140(%r10)
	0x1f: prefetchw 0x180(%r10)   
	...
↗	0xc70: movslq %edi,%rbx
│	0xc73: movsbl 0x10(%r8,%rbx,1),%r9d
│	0xc79: test   %r9d,%r9d
│	0xc7c: jl     0x000000010ba8fd58
│	0xc82: mov    %r9w,0x10(%rdx,%rbx,2)
│	0xc88: movsbl 0x11(%r8,%rbx,1),%r9d
│	0xc8e: test   %r9d,%r9d
│	0xc91: jl     0x000000010ba8fd63
│	0xc97: mov    %r9w,0x12(%rdx,%rbx,2)
│	0xc9d: movsbl 0x12(%r8,%rbx,1),%r9d
│	0xca3: test   %r9d,%r9d
│	0xca6: jl     0x000000010ba8fd69
│	0xcac: mov    %r9w,0x14(%rdx,%rbx,2)
│	0xcb2: movsbl 0x13(%r8,%rbx,1),%r9d
│	0xcb8: test   %r9d,%r9d
│	0xcbb: jl     0x000000010ba8fd5c
│	0xcc1: mov    %r9w,0x16(%rdx,%rbx,2)
│	0xcc7: movsbl 0x14(%r8,%rbx,1),%r9d
│	0xccd: mov    %edi,%ecx
│	0xccf: add    $0x4,%ecx        
│	0xcd2: test   %r9d,%r9d
│	0xcd5: jl     0x000000010ba8fd6e
│	0xcdb: mov    %r9w,0x18(%rdx,%rbx,2)
│	0xce1: movsbl 0x15(%r8,%rbx,1),%r9d
│	0xce7: test   %r9d,%r9d
│	0xcea: jl     0x000000010ba8fd65
│	0xcec: mov    %r9w,0x1a(%rdx,%rbx,2)
│	0xcf2: movsbl 0x16(%r8,%rbx,1),%r9d
│	0xcf8: test   %r9d,%r9d
│	0xcfb: jl     0x000000010ba8fd6b
│	0xcfd: mov    %r9w,0x1c(%rdx,%rbx,2)
│	0xd03: movsbl 0x17(%r8,%rbx,1),%r9d
│	0xd09: test   %r9d,%r9d
│	0xd0c: jl     0x000000010ba8fd5e
│	0xd0e: mov    %r9w,0x1e(%rdx,%rbx,2)
│	0xd14: add    $0x8,%edi        
│	0xd17: cmp    $0x3f9,%edi
│	0xd1d: jl     0xc70
│	0xd23: cmp    $0x400,%edi
╰	0xd29: jge    0x000000010ba8fb91
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;First note that &lt;code class=&quot;highlighter-rouge&quot;&gt;mov $0x200, %ecx&lt;/code&gt; moves the decimal &lt;code class=&quot;highlighter-rouge&quot;&gt;512&lt;/code&gt; into &lt;code class=&quot;highlighter-rouge&quot;&gt;%ecx&lt;/code&gt; and the &lt;code class=&quot;highlighter-rouge&quot;&gt;shl&lt;/code&gt; that follows changes this to &lt;code class=&quot;highlighter-rouge&quot;&gt;4096&lt;/code&gt;.
The &lt;code class=&quot;highlighter-rouge&quot;&gt;xor %rax, %rax&lt;/code&gt; instruction &lt;a href=&quot;https://stackoverflow.com/a/33668295/368220&quot;&gt;zeros&lt;/a&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;%al&lt;/code&gt;.
The &lt;code class=&quot;highlighter-rouge&quot;&gt;rep rex.W stos %al,%es:(%rdi)&lt;/code&gt; instruction iterates &lt;code class=&quot;highlighter-rouge&quot;&gt;%ecx&lt;/code&gt; (= 4096) times, each time copying the zeros from &lt;code class=&quot;highlighter-rouge&quot;&gt;%al&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;%es:(%rdi)&lt;/code&gt; and incrementing &lt;code class=&quot;highlighter-rouge&quot;&gt;%rdi&lt;/code&gt;.
To summarize, this block initializes the &lt;code class=&quot;highlighter-rouge&quot;&gt;char[2048]&lt;/code&gt; array (each char takes up two bytes).&lt;/p&gt;

&lt;p&gt;The second thing to notice is that C2 unrolled the loop body 8 times.
Specifically, the sign of each byte is checked individually and a jump is performed if the sign is negative.&lt;/p&gt;

&lt;h4 id=&quot;graalvm&quot;&gt;GraalVM&lt;/h4&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  0x38: mov        $0xffffffff,%r10d
↗ 0x70: lea        0x8(%r13),%r13
│ 0x74: cmp        %rbp,%r13
│ 0x77: jg         0x000000010e10cc8a
│ 0x7d: vmovdqu    (%rbx,%r13,4),%ymm0
│ 0x83: vpxor      %xmm1,%xmm1,%xmm1
│ 0x87: vpcmpgtd   %ymm0,%ymm1,%ymm0
│ 0x8b: vpmovmskb  %ymm0,%r14d
│ 0x8f: test       %r10d,%r14d
╰ 0x92: je         0x70
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Even though the Java loop contains a condition and multiple exists, Graal was able to compile this to AVX2 instructions.
The &lt;code class=&quot;highlighter-rouge&quot;&gt;vmovdqu&lt;/code&gt; instruction moves 256 bits (32 bytes) to the &lt;code class=&quot;highlighter-rouge&quot;&gt;%ymm0&lt;/code&gt; register.
The &lt;code class=&quot;highlighter-rouge&quot;&gt;vpxor&lt;/code&gt; instruction effectively zeros the &lt;code class=&quot;highlighter-rouge&quot;&gt;%xmm1&lt;/code&gt; register.
&lt;!-- Keep in mind that `%xmm1` is the lower half of `%ymm1`. --&gt;
The &lt;code class=&quot;highlighter-rouge&quot;&gt;vpcmpgtd&lt;/code&gt; instruction compares each signed DWORD in &lt;code class=&quot;highlighter-rouge&quot;&gt;%ymm0&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;%ymm1&lt;/code&gt; and stores the result in the corresponding DWORD in &lt;code class=&quot;highlighter-rouge&quot;&gt;%ymm0&lt;/code&gt;.
&lt;!--If the first DWORD is larger than the second, then the corresponding DWORD in `%ymm0` is set to all 1, otherwise 0.--&gt;
&lt;!--Since the lower half of `%ymm1` is zero'd, the lower half of `%ymm0` remains unchanged.--&gt;
The &lt;code class=&quot;highlighter-rouge&quot;&gt;vpmovmskb&lt;/code&gt; instruction moves the most significant bit of each byte of the source operand &lt;code class=&quot;highlighter-rouge&quot;&gt;%ymm0&lt;/code&gt; (256-bits) to the destination operand &lt;code class=&quot;highlighter-rouge&quot;&gt;%r14d&lt;/code&gt; (32-bits).
The &lt;code class=&quot;highlighter-rouge&quot;&gt;test&lt;/code&gt; instruction sets the zero flag if the bitwise AND of its operands &lt;code class=&quot;highlighter-rouge&quot;&gt;%r10d&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;%r14d&lt;/code&gt; is zero, which is the case only when &lt;code class=&quot;highlighter-rouge&quot;&gt;%r14d&lt;/code&gt; is zero.
The &lt;code class=&quot;highlighter-rouge&quot;&gt;je&lt;/code&gt; instruction jumps to the start of the loop if the zero flag is set.&lt;/p&gt;

&lt;p&gt;To summarize: each iteration of the loop processes 32 bytes.
Each of the 32 bytes is mapped to 0 if the byte represents a value greater than or equal to 0 and mapped to 1 otherwise.
These 32 bits are collected into a single register.
If this register is zero, i.e. if all original bytes were greater than or equal to 0, the loop is repeated.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;We compared the C2 JIT-compiler (Java 8u241) to the Graal JIT-compiler (GraalVM EE 20.0.0) on four benchmarks: escape analysis, data-flow analysis, inlining, and vectorization.
On all benchmarks, the Graal JIT-compiler outperformed the C2 JIT-compiler:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;In the escape analysis benchmark, Graal used &lt;em&gt;partial escape analysis&lt;/em&gt; to avoid object construction.&lt;/li&gt;
  &lt;li&gt;In the data-flow analysis benchmark, Graal used &lt;em&gt;data flow analysis&lt;/em&gt; to remove unreachable code.&lt;/li&gt;
  &lt;li&gt;In the inlining benchmark, Graal inlined a megamorphic call site to avoid call overhead.&lt;/li&gt;
  &lt;li&gt;In the vectorization benchmark, C2 unrolled the loop but Graal vectorized the loop.&lt;/li&gt;
&lt;/ul&gt;

&lt;!--
## Acknowledgements

This style of writing is very much inspired by Aleksey Shipilev's _JVM Anatomy Quark_ series, head over to his blog if you're interested in performance engineering.
The idea of comparing Graal to C2 comes from Ionut Balosin.
In this blog post I wanted to repeat the experiments on a more recent version of GraalVM EE, share the code for the experiments, and give more information about what is going on under the hood.
--&gt;</content><author><name></name></author><category term="graal" /><category term="c2" /><category term="jit" /><category term="compiler" /><category term="optimization" /><summary type="html">GraalVM claims to “Run Programs Faster Anywhere 🚀”. Indeed, existing applications often run faster on GraalVM compared to OpenJDK and Oracle JDK. For example, Twitter reports 11 percent reduction in CPU utilization by using Graal CE. With GraalVM EE they were even able to reduce CPU utilization by a staggering 20 percent. What often remains undiscussed, however, is how GraalVM exactly achieves this performance speedup. In this blog post I try to answer this question by comparing GraalVM EE 20.0.0 to Oracle Java 8u241 on a number of benchmarks.</summary></entry></feed>