Is Python "Compiled"?

Hannah Schroeter hannah at schlund.de
Thu Feb 8 13:06:25 EST 2001


Hello!

In article <xOAg6.11196$x4.177559 at e420r-atl2.usenetserver.com>,
Steve Holden <sholden at holdenweb.com> wrote:
>[...]

>Well, LISP is kind of special: the typical list representation and
>car()/cdr() operations are pretty efficient if properly compiled. But most
>interpreted languages

A language can't be classified as interpreted or compiled. Implementations
can be.

Lisp has one implementation (e.g. sbcl) which can both interpret,
compile to bytecode or compile to native code. Another implementation
(e.g. clisp) can only interpret or compile to bytecode. There could
be an implementation that would only do minimal compilation (only that
which is required by the standard, mostly macro expansion) and would
thus be an almost only interpreting implementation. Yet another possibility
would be compiling everything to native, even forms from the interactive
REPL.

>end up "compiling" down into calls to the interpreter
>bytecode routines, which doesn't save much space or time. That was certainly
>true for Icon, anyway, and I suspect would be for other similar languages.

Again, that's a property of implementations, not of languages.
Sure, some languages might be especially difficult to compile to
efficient native code (or efficient bytecodes), others make it easier.

>JIT might or might not be a win for Python, but programs would still end up
>lugging a lot of support code around,

Support code, yes. Many (esp. the free ones) Lisp systems don't create
standalone executables but images to be run with the runtime, which
provides low level functionality like image loading, GC, low level
object representation, predefined functions (as long as they are not
implemented in Lisp themselves). Many Smalltalk implementations do
the same, and still, that's no hinderance in using native processor
instructions in the image file, amounting to more than just calling
one runtime function after the other.

>and without static typing a lot of
>decisions still have to be deferred until run-time.

See again Smalltalk. That's an area where many gains are possible
to make. One is static analysis: if, in a method call x.y(), the
compiler can infer that the type of x is A, the compiler can statically
code a call to A's y() method. If the compiler knows that x can be of
two types B or C, it can code something like
  if (typeof(x) is B)
    call B's y() method
  else
    call C's y() method
which on many processors is even faster than C++'s vtables (one
indirect jump), because for many branch prediction units, indirect
jumps are poison. (The SmallEiffel people do *all* method dispatches
using such a technique and found the break even point [where vtable
would be better] to be over around 50 possible object types).
The other comes from the JIT world. At precompilation time, code
an instrumented method call:
  runtime_call_method(x, "y", (no arguments))
That can gather evidence about the real call patterns (i.e. which
methods get really called for how often), after some time, it will
change that code to something resembling that evidence:
  call B's checked y() method
where
  B's checked y() method is:
    1:
    if (typeof(self) is NOT B)
      jump out to the runtime system indicating the type mismatch, passing
      self to the RTS for re-dispatching
    2:
    here, the real code of the y() method follows.

(i.e. methods are two-entry-point functions, the first is the checked
entry point, the second is unchecked [compiler is statically sure about
the type)

The code after 1 can usually translated to less than a handful of machine
instructions.

>regards
> Steve

Kind regards,

Hannah.



More information about the Python-list mailing list