2

What kind of a JIT compiler is used by PyPy?

  1. The tracing JIT or something like Java HotSpot Virtual Machine.
  2. Per method call kind.
  3. Something like Econo JIT Compiler of .NET Framework.
Yarl
  • 728
  • 1
  • 7
  • 26

2 Answers2

4

According to this blog post it is a tracing jit compiler;

It's worth it at this point to read up on how tracing JIT compilers work. Here's a brief explanation: The interpreter is usually running your interpreter code as written. When it detects a loop of code in the target language is executed often, that loop is considered "hot" and marked to be traced. The next time that loop is entered, the interpreter gets put in tracing mode where every executed instruction is logged.

When the loop is finished, tracing stops. The trace of the loop is sent to an optimizer, and then to an assembler which outputs machine code. That machine code is then used for subsequent loop iterations.

This machine code is often optimized for the most common case, and depends on several assumptions about the code. Therefore, the machine code will contain guards, to validate those assumptions. If a guard check fails, the runtime falls back to regular interpreted mode.

Community
  • 1
  • 1
Roland Smith
  • 42,427
  • 3
  • 64
  • 94
1

As stated in Roland Smith's answer, PyPy uses a form of tracing JIT compiler. A tracing JIT compiles only the "used parts" by definition.

Mind you, this doesn't make it any less real than some hypothetical JIT that starts off by compiling the whole program during startup. Indeed, there exists several good reasons to avoid this strategy.

Startup time

Startup is likely to become significantly slower, since the compiler has to process the entire program even though a significant portion of it may never be executed. This is true irrespective of whether the JIT starts from source code or bytecode.

Lost opportunities for optimization

Many programming languages – particularly dynamic languages, such as JavaScript – can benefit tremendously from a compiler that is able to adapt to the program's runtime properties. Forcing the JIT to compile everything on startup tends to preclude interesting optimizations that rely on having access to, say, type information collected at runtime.


It sounds like your distiction of "real vs economic" might stem from a misunderstanding of the distinction between a method JIT and a tracing JIT.

In a method JIT, such as Oracle's HotSpot, the unit of compilation is the method (or function, or procedure, or whatever you want to call it). This is a tradition carried over from AOT compilers. Method JIT's rely heavily on inlining to expose more code to the optimizer. It's not unusual for a method JIT to defer compilation of a method until it is actually called.

By contrast, a tracing JIT observes and records the sequences of instructions (typically some kind of bytecode) that are actually executed as the program runs. Unlike a method JIT, which must explicitly choose to inline method calls, inlining is a convenient side-effect of having a tracing JIT. Much like how a method JIT can defer compilation of a method, a tracing JIT will typically wait for some execution count threshold before a trace is compiled to machine code, as it could otherwise waste precious time compiling traces that will never run again (such as a hot loop that runs once at the beginning of main!).

Please note that the brief explanations above are significantly simplified; if you're interested in the subject, I encourage you to study both JIT strategies in more detail.

Martin Törnwall
  • 9,299
  • 2
  • 28
  • 35
  • Thank you for your explanation. There is certain probability for deeper study of both JIT strategies in the future as you suggested. I am interested but I have more prior work to do this time. – Yarl Jun 01 '16 at 17:58