falcon: an optimizing java jit · why you should use llvm to build a jit • proven stability,...

66
Philip Reames Azul Systems FALCON: AN OPTIMIZING JAVA JIT

Upload: others

Post on 18-Feb-2020

12 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

Philip Reames

Azul Systems

FALCON: AN OPTIMIZING JAVA JIT

Page 2: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

AGENDA

• Intro to Falcon

• Why you should use LLVM to build a JIT

• Common Objections (and why they’re mostly wrong)

2

Page 3: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

WHAT IS FALCON?

• Falcon is an LLVM based just-in-time compiler for Java bytecode.

• Shipping on-by-default in the Azul Zing JVM.

• Available for trial download at: www.azul.com/zingtrial/

3

Page 4: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

THIS TALK IS ABOUT LESSONS LEARNED, BOTH TECHNICAL AND PROCESS

4

Page 5: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

ZING VM BACKGROUND

• A hotspot derived JVM with an awesome GC (off topic)

• Multiple tiers of execution

Interpreter Tier1 Compiler

Tier2 Compiler

Rapidly generated code to collect profiling quickly

Run once bytecode and rare events

Compile hot methods for peak performance

5

Page 6: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

BUSINESS NEED

• The existing C2 compiler is aging poorly

• vectorization (a key feature of modern x86_64) is an afterthought

• very complicated codebase; "unpleasant" bug tails the norm

• difficult to test in isolation

• Looking to establish a competitive advantage

• Long term goal is to outperform competition

• Velocity of performance improvement is key

6

Page 7: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

DEVELOPMENT TIMELINE

April 2014 Proof of concept completed (in six months)

Feb 2015 Mostly functionally complete

April 2016 Alpha builds shared with selected customers

Dec 2016 Product GA (off by default)

April 2017 On by default

Team size: 4-6 developers, ~20 person years invested

7

Page 8: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

TEAM EFFORT

Falcon Development

Bean Anderson Philip Reames Chen Li Sanjoy Das Igor Laevsky Artur Pilipenko Daniel Neilson Anna Thomas Serguei Katkov Maxim Kazantsev Daniil Suchkov Michael Wolf Leela Venati Kris Mok Nina Rinskaya

+ VM development team

+ Zing QA

+ All Azul (E-Staff, Sales, Support, etc..)

8

Page 9: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

9

Various application benchmarks + SPECjvm + Dacapo Collected on a mix of haswell and skylake machines

0%

20%

40%

60%

80%

100%

120%

140%

160%

180%

200%

Zing 17.08 vs Oracle 8u121

Page 10: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

WHY YOU SHOULD USE LLVM TO BUILD A JIT

• Proven stability, widespread deployments

• Active developer community, support for new micro-architectures

• Proven performance (for C/C++)

• Welcoming to commercial projects

10

Page 11: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

COMMON OBJECTIONS

• "LLVM doesn't support X“

• “LLVM is a huge dependency"

• "We added an LLVM backend; it produced poor code"

• "LLVM generates too much code"

• "LLVM is a slow JIT“

• “My language has feature X (which requires a custom compiler)”

11

Page 12: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

LLVM DOESN'T SUPPORT X

Objection 1 of 6

12

Page 13: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

FIRST, A BIT OF SKEPTICISM...

13

• Is this something you can express in C? If so, LLVM supports it.

e.g. deoptimization via spill to captured on-stack buffer

buf = alloca(…); buf[0] = local_0; … a->foo(buf, actual_args…)

The real question, is how well is it supported?

Page 14: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

FUNCTIONAL CORNER-CASES

• If you can modify your ABI (calling conventions, patching sequences, etc..), your life will be much easier.

• You will find a couple of important hard cases. Ours were:

• “anchoring" for mixed stack walks

• red-zone arguments to assembler routines

• support for deoptimization both checked and async

• GC interop

14

Page 15: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

BE WARY OF OVER DESIGN

15

• Common knowledge that quality of safepoint lowering matters.

• gc.statepoint design

• Major goal: allow in register updates

• Topic of 2014 LLVM Dev talk

• 2+ person years of effort

• It turns out that hot safepoints are inliner bug.

Page 16: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

GET TO FUNCTIONAL CORRECTNESS FIRST

• Priority 1: Implement all interesting cases, get real code running

• Priority 2: Add tests to show it continues working

• Design against an adversarial optimizer.

• Be wary of over-design, while maintaining code quality standards.

16 See backup slides for more specifics on this topic.

Page 17: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

LLVM IS A HUGE DEPENDENCY

Objection 2 of 6

17

Page 18: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

18

• Potentially a real issue, but depends on your definition of large.

• From our shipping product:

libJVM = ~200mb

libLLVM = ~40mb

• So, 20% code size increase.

Page 19: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

WE ADDED AN LLVM BACKEND; IT PRODUCED POOR CODE

Objection 3 of 6

19

Page 20: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

IMPORTANCE OF PROFILING

• Tier 1 collects detailed profiles; Tier 2 exploits them

• 25% or more of peak application performance

20

Page 21: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

PRUNE UNTAKEN PATHS

• Handle rare events by returning to lower tier, reprofiling, and then recompiling.

Interpreter

Tier1 Code Tier2 Code

Rare Events

%ret = call i32 @llvm.experimental.deoptimize() ["deopt"(..)] ret i32 %ret

21

Page 22: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

PREDICATED DEVIRTUALIZATION

switch (type(o)) case A: A::foo(); case B: B::foo(); default: o->foo();

Critical for Java, where everything is virtual by default

switch (type(o)) case A: A::foo(); case B: B::foo(); default: @deoptimize() [“deopt”(…)]

22

Page 23: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

IMPLICIT NULL CHECKS

%is.null = icmp eq i8* %p, null br i1 %is.null, label %handler, label %fallthrough, !make.implicit !{}

test rax, rax jz <handler> rsi = ld [rax+8]

rsi = ld [rax+8] fault_pc __llvm_faultmaps[fault_pc] -> handler

handler: call @__llvm_deoptimize

23

Page 24: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

LOCAL CODE LAYOUT

• branch_weights for code layout

• Sources of slow paths:

• GC barriers, safepoints

• handlers for builtin exceptions

• result of code versioning

• 50%+ of total code size

Hot cold hot cold hot cold

24

hot hot hot cold cold cold

Page 25: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

GLOBAL CODE LAYOUT

• Best to put cold code into it's own section

See: LLVM back end for HHVM/PHP, LLVM Dev Conf 2015

func1-hot func1-cold func2-hot func2-cold func3-hot func3-cold

25

func1-hot func2-hot func3-hot func1-cold func2-cold func3-cold

Page 26: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

EXPLOITING SEMANTICS

• LLVM supports a huge space of optional annotations

• Both metadata and attributes

• ~6-12 month effort

Performance Analysis

Root Cause Issue

Add Annotation

Fix Uncovered Miscompiles

26

Page 27: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

DEFINING A CUSTOM PASS ORDER

• Requires careful thought and experimentation.

• MCJIT's OptLevel is not what you want.

• PassManagerBuilder is tuned for C/C++!

• May expose some pass ordering specific bugs

27

legacy::PassManager PM; PM.add(createEarlyCSEPass()); ... PM.run(Module)

Page 28: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

EXPECT TO BECOME AN LLVM DEVELOPER

• You will uncover bugs, both performance and correctness

• You will need to fix them.

• Will need a downstream process for incorporating and shipping fixes.

28 See backup slides for more specifics on this topic.

Page 29: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

STATUS CHECK

• We've got a reasonably good compiler for a c-like subset of our source language.

• We're packaging a modified LLVM library.

• This is further than most projects get.

29

Page 30: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

QUICK EXAMPLE

public int intsMin() { int min = Integer.MAX_VALUE; for (int i = 0; i < a_I.length; i++) { min = min > a_I[i] ? a_I[i] : min; } return min; }

4x faster than competition on Intel Skylake

30

Page 31: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

"LLVM GENERATES TOO MUCH CODE"

Objection 4 of 6

31

Page 32: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

CALLING ALL LLVM DEVELOPERS...

32

• We regularly see 3-5x larger code compared to C2.

• Partly as a result of aggressive code versioning.

• But also, failure to exploit:

• mix of hot and cold code, need selective Oz

• lots and lots of no-return paths

• gc.statepoint lowering vs reg-alloc

• code versioning via deopt (unswitch, unroll, vectorizer)

Page 33: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

LLVM IS A SLOW JIT

Objection 5 of 6

33

Page 34: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

34

• Absolutely. LLVM is not suitable for a first tier JIT.

• That's not what we have or need.

• We use the term "in memory compiler" to avoid confusion.

Page 35: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

SYSTEM INTEGRATION

• VM infrastructure moderates impact

• The tier 2 compiler sees a small fraction of the code.

• Background compilation on multiple compiler threads.

• Prioritized queueing of compilation work

• Hotness driven fill-in of callee methods

• This stuff is standard (for JVMs). Nothing new here.

35

Page 36: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

IN PRACTICE, MOSTLY IGNORE-ABLE

• Typical compile times around 100ms.

• Extreme cases in the seconds to low minute range.

• At the extreme, that's (serious) wasted CPU time, but nothing else.

36

Page 37: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

WAIT, YOU DO WHAT?

• There are cases where this isn't good enough.

• a popular big-data analytics framework spawns a JVM per query

• multi-tenancy environments can spawn 1000s of JVMs at once

• Improving compile time is hard. So what do we do?

37

Page 38: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

CACHED COMPILES

• Reuse compiled code across runs.

• Profiling continues to apply.

• No decrease in peak performance.

• Planned to ship in a future version of Zing.

Credit for inspiration goes to the Pyston project and their article "Caching object code". https://blog.pyston.org/2015/07/14/caching-object-code

38

After all, our "in memory compiler" does produce normal object files.

Page 39: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

MY LANGUAGE HAS FEATURE X (WHICH REQUIRES A CUSTOM COMPILER)

Objection 6 of 6

39

Page 40: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

LANGUAGE SPECIFIC DEFICIENCIES

• LLVM has been tuned for certain languages

• The more different your language, the more work needed.

• For Java, our key performance problems were:

• range checks

• null checks

• devirtualization & inlining

• type based optimizations

• deoptimization

40

Page 41: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

DO YOU ACTUALLY HAVE A PROBLEM?

• Try the naive version, seriously try it!

• Very useful to try different C++ implementations

• requires good knowledge of Clang

• may find a viable implementation strategy

• may provide insight into what optimizer finds hard

• Check to see if existing metadata/attributes are relevant

41

Page 42: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

CUSTOM ATTRIBUTES/METADATA

• Is there a single key missing fact? Or a small set thereof?

• A lot of advantages:

• Factoring for long term branching

• May be upstreamable

• Easy to functionally test

• Serialization

42

Examples from our tree: LICM isGuaranteedToExecute "allocation-site" "deopt-on-throw" "known-value" "java-type"=“XYZ”

Page 43: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

METADATA HEALING

• Optimizer tends to strip metadata it doesn't understand.

• Don't try to change this

• Need a mechanism to "heal" previously stripped metadata

43 See backup slides for more on this topic

Page 44: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

CALLBACKS

Optional<FieldInfo>

getKnownValueKeyDependent(llvm::LLVMContext &C,

KnownValueID BaseObj,

int64_t Offset,

uint64_t Size);

44

Narrow interface between optimizer and containing runtime

Page 45: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

CALLBACKS

• Primarily used for metadata healing

• But also useful for type system specific optimizations

• Resist temptation to add them freely.

• Each one should be strongly and continuously justified.

• We have 24 total. And that's too many.

• Optimizer can visit dead code (Critically Important)

• Fuzz this interface. Seriously, fuzz it!

45

Page 46: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

IMPLICATIONS FOR REPLAY

Replay is an absolutely essential debugging and diagnostic tool

$ opt –O3 -S input.ll

To preserve replay w/callbacks, need a query-log mechanism.

$ opt –O3 -S input.ll --read-query-log-from-file=input.ll.queries

46

Page 47: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

EMBEDDED HIGH LEVEL IR

• "Abstraction" functions

• Opaque by default to the optimizer

• Can be first class citizens with builtin knowledge

• Useful for building certain classes of high level optimizations

47

declare i8 addrspace(1)* @azul.resolve_virtual(i8 addrspace(1)* %receiver, i64 %vtable_index) nounwind noinline readonly "late-inline"="2" "gc-leaf-function"

Page 48: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

EMBEDDED HIGH LEVEL IR

• Enable high level transforms such as:

• devirtualization

• object elision

• allocation sinking & partial escape analysis

• lock coarsening & elision

• Most of the above expressed as custom passes

48 See backup slides for discussion of the tradeoffs around custom passes

Page 49: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

A (SLIGHT) CHANGE IN VIEW ON ABSTRACTIONS

• Useful for rapid evolution and prototyping

• But each is an optimization barrier until lowered

• As few as you can reasonably manage long term

• Lower early in the pipeline

• Minimize number of unique lowering points

49

Page 50: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

CONCLUSION

For the right use case, LLVM can be used to build a production quality JIT which is performance competitive with state of the art.

50

Page 51: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

QUESTIONS?

51

Page 52: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

BACKUP SLIDES

52

Page 53: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

ASIDE: STAFFING

• Hiring a team from within the existing community is hard, slow, and expensive.

• Expect to train most of your team; including yourself.

53

Page 54: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

SO IT'S COMPLETE, IS IT CORRECT?

• Design against a adversarial optimizer.

• Don't fall for "no real compiler would do that".

• You'll be wrong; if not now, later.

54

Page 55: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

A RECOMMENDATION

Implement the cases claimed to be unreasonable. :)

55

Page 56: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

HIGH VALUE TESTING TECHNIQUES

• Compile everything (not standard for high tier compilers) in a very large corpus w/a Release+Asserts build

• 1500+ JARs, every method, every class

• Finds many subtle invariant violations

• Randomly generated test cases (Fuzzing) works.

• By far cheapest way to find miscompile bugs.

• Good way to find regressions quickly.

56

Page 57: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

57

“Be Wary of Overdesign” continued…

Page 58: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

ONE WORD OF CAUTION

• While ugly design is expected, your code should be production quality and well tested.

• Surprisingly large amounts of our initial prototype code made it into the final product.

• "of course we'll rewrite this" only works if you have perfect knowledge

• Still not an excuse for over-design.

58

Page 59: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

MANAGING BRANCHES

• Daily integrations are strongly encouraged.

• Key considerations:

• LLVM evolves quickly, internal APIs are not stable

• Isolating regressions

• Revert-to-green culture *for recent changes*

• Can be very time consuming if not carefully arranged.

59

Page 60: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

ONE WORKING BRANCH DESIGN

pristine -- plain LLVM passing make check (w/our build config)

merge-unstable - merged with local changes (conflict resolutions)

testing - VM merge and basic tests pass (catches all API changes)

merge-stable - last point known to pass all tests

master

60

Page 61: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

FRONTEND INTRINSICS

• Replace body of A::foo with hand written IR

• Here be Dragons:

• Major implications for correctness testing

• Too easy to side-step hard issues

• Hard Lessons:

• Express all preconditions in source language

• Intrinsify only the critical bit

• Be willing to change core libraries early

61

Page 62: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

METADATA HEALING TRADEOFFS

• Pros:

• Robust to upstream changes

• Robust to pass order changes

• Works for custom and upstream metadata

• Testable

• Cons:

• Wastes compile time

• Can't always recover lost information

62

Page 63: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

Custom passes continued…

63

Page 64: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

CUSTOM PASSES

Pros:

• Easy to implement

• Handle language specific IR patterns

• Required for certain high level optimizations

Cons:

• Simplicity is often deceptive

• May cover a hard problem which needs solved

• Not in the default pipeline, major testing implications

64

Page 65: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

KEY LESSON: SHORT VS LONG TERM

• Improving existing passes is the right long term answer.

• Not all problems need long term solutions.

• A specialized pass generally gets 80% of cases, much sooner.

65

Page 66: FALCON: AN OPTIMIZING JAVA JIT · WHY YOU SHOULD USE LLVM TO BUILD A JIT • Proven stability, widespread deployments • Active developer community, support for new micro-architectures

KEY LESSON: TESTING

• Code that runs rarely is often buggy. Subtly so.

• Unit testing only goes so far.

• Our painful lessons:

• Inductive Range Check Elimination (IRCE)

• Loop Predication

• (Only) three options:

• Extensive, exhausting testing via fuzzers

• Well factored shallow code

• Minimize language specific code

66