Here, you can use “virtual machine” as in “Java Virtual Machine”, not as in virtualization. We will play with the virtual machine described in the paper Tracing the Meta-Level: PyPy’s Tracing JIT Compiler by C.F. Bolz, A. Cuni, M. Fijalkowski and A. Rigo (it’s a great read by the way).
PyPy is a fascinating project, too complex to describe here. Among other things, PyPy can take any interpreter written in a subset of Python, translate it to C, and automatically generate a JIT compiler for this language. Does it sound too good to be true? Let’s try this.
- grab PyPy source code
- create the interpreter in pypy/translator/goal/target-toy.py with the following code:
</pre>
<pre style="text-align: justify;">import os, sys
import autopath
import py
# these are the opcodes for the interpreted language
JUMP_IF_A = 1
MOV_A_R = 2
MOV_R_A = 3
ADD_R_TO_A = 4
DECR_A = 5
RETURN_A = 6
<em>from pypy.rlib.jit import JitDriver tlrjitdriver = JitDriver(greens = ['pc', 'bytecode'], reds = ['a', 'regs'])</em>
# the main interpreter loop
def interpret(bytecode, a):
regs = [0] * 256
pc = 0
while True:
<em> tlrjitdriver.jit_merge_point(bytecode=bytecode, pc=pc, a=a, regs=regs) </em> opcode = bytecode[pc]
pc += 1
if opcode == JUMP_IF_A:
target = bytecode[pc]
pc += 1
if a:
<em> if target<pc: tlrjitdriver.can_enter_jit(bytecode=bytecode, pc=target, a=a, regs=regs) </em> pc = target
elif opcode == MOV_A_R:
n = bytecode[pc]
pc += 1
regs[n] = a
elif opcode == MOV_R_A:
n = bytecode[pc]
pc += 1
a = regs[n]
elif opcode == ADD_R_TO_A:
n = bytecode[pc]
pc += 1
a += regs[n]
elif opcode == DECR_A:
a -= 1
elif opcode == RETURN_A:
return a
# __________ Entry point __________
def entry_point(argv):
# the program we want to interpret
# it computes the square of its argument
bytecode = [
MOV_A_R, 0, # i = a
MOV_A_R, 1, # copy of ’a’
# 4:
MOV_R_A, 0, # i--
DECR_A,
MOV_A_R, 0,
MOV_R_A, 2, # res += a
ADD_R_TO_A, 1,
MOV_A_R, 2,
MOV_R_A, 0, # if i!=0: goto 4
JUMP_IF_A, 4,
MOV_R_A, 2,
RETURN_A
]
result = interpret(bytecode, int(argv[1]))
print result
return 0
def jitpolicy(driver):
from pypy.jit.metainterp.policy import JitPolicy
return JitPolicy()
# _____ Define and setup target ___
def target(*args):
return entry_point, None
# main function, if this script is called from the command line
if __name__ == '__main__':
entry_point(sys.argv)</pre>
<div><span style="color: #000000;">
Interesting, short but nice example
thanks :)
Small question, it appears that the native pypy runs are returning a different value at the end? Have I missed something?
That’s right, because the C and C-jit versions are 32-bit binaries and the translation process probably does not take into account the overflow.
Hey.
RPython has well documented overflow semantics – you can get overflow detection, but not automatic promotion to long. Here is the description http://codespeak.net/pypy/dist/pypy/doc/coding-guide.html#integer-types
It seems a little unfair to do the comparison in that way, surely arithmetic with more digits is more computationally expensive.
Will you be doing more articles about using PyPy?
Probably. Right now I’m just playing with it, but I’d like to dive deeper.
It’s great to get the wrong answer quickly :>
PyPy FAILED :
http://permalink.gmane.org/gmane.comp.lang.lua.general/62915
is it really necessary to sound like you’re commenting on youtube?
follow-up:
http://comments.gmane.org/gmane.comp.lang.lua.general/62926
Yep finally …