Commits

Alexander Hesse  committed a0b190c

Moved spli to toplevel

  • Participants
  • Parent commits b43d733
  • Branches split-rpython

Comments (0)

Files changed (27)

File rpython/jit/tl/spli/__init__.py

Empty file removed.

File rpython/jit/tl/spli/examples.py

-
-def f():
-    return 1
-
-print f()
-
-def adder(a, b):
-    return a + b
-
-def while_loop():
-    i = 0
-    while i < 10000000:
-        i = i + 1
-    return None
-
-while_loop()

File rpython/jit/tl/spli/execution.py

-from rpython.jit.tl.spli import interpreter, objects, pycode
-
-
-def run_from_cpython_code(co, args=[], locs=None, globs=None):
-    space = objects.DumbObjSpace()
-    pyco = pycode.Code._from_code(space, co)
-    return run(pyco, [space.wrap(arg) for arg in args], locs, globs)
-
-def run(pyco, args, locs=None, globs=None):
-    frame = interpreter.SPLIFrame(pyco, locs, globs)
-    frame.set_args(args)
-    return get_ec().execute_frame(frame)
-
-
-def get_ec():
-    ec = state.get()
-    if ec is None:
-        ec = ExecutionContext()
-        state.set(ec)
-    return ec
-
-
-class State(object):
-
-    def __init__(self):
-        self.value = None
-
-    def get(self):
-        return self.value
-
-    def set(self, new):
-        self.value = new
-
-state = State()
-
-
-class ExecutionContext(object):
-
-    def __init__(self):
-        self.framestack = []
-
-    def execute_frame(self, frame):
-        self.framestack.append(frame)
-        try:
-            return frame.run()
-        finally:
-            self.framestack.pop()

File rpython/jit/tl/spli/interpreter.py

-import os
-from rpython.tool import stdlib_opcode
-from rpython.jit.tl.spli import objects, pycode
-from rpython.rlib.unroll import unrolling_iterable
-from rpython.rlib.jit import JitDriver, promote, dont_look_inside
-from rpython.rlib.objectmodel import we_are_translated
-
-opcode_method_names = stdlib_opcode.host_bytecode_spec.method_names
-unrolling_opcode_descs = unrolling_iterable(
-    stdlib_opcode.host_bytecode_spec.ordered_opdescs)
-HAVE_ARGUMENT = stdlib_opcode.host_HAVE_ARGUMENT
-
-compare_ops = [
-    "cmp_lt",   # "<"
-    "cmp_le",   # "<="
-    "cmp_eq",   # "=="
-    "cmp_ne",   # "!="
-    "cmp_gt",   # ">"
-    "cmp_ge",   # ">="
-#    "cmp_in",
-#    "cmp_not_in",
-#    "cmp_is",
-#    "cmp_is_not",
-#    "cmp_exc_match",
-]
-unrolling_compare_dispatch_table = unrolling_iterable(
-    enumerate(compare_ops))
-
-jitdriver = JitDriver(greens = ['instr_index', 'code'],
-                      reds = ['frame'],
-                      virtualizables = ['frame'])
-
-
-class BlockUnroller(Exception):
-    pass
-
-class Return(BlockUnroller):
-
-    def __init__(self, value):
-        self.value = value
-
-class MissingOpcode(Exception):
-    pass
-
-class SPLIFrame(object):
-
-    _virtualizable2_ = ['value_stack[*]', 'locals[*]', 'stack_depth']
-
-    @dont_look_inside
-    def __init__(self, code, locs=None, globs=None):
-        self.code = code
-        self.value_stack = [None] * code.co_stacksize
-        self.locals = [None] * code.co_nlocals
-        if locs is not None:
-            self.locals_dict = locs
-        else:
-            self.locals_dict = {}
-        if globs is not None:
-            self.globs = globs
-        else:
-            self.globs = {}
-        self.stack_depth = 0
-
-    def set_args(self, args):
-        for i in range(len(args)):
-            self.locals[i] = args[i]
-
-    def run(self):
-        self.stack_depth = 0
-        try:
-            self._dispatch_loop()
-        except Return, ret:
-            return ret.value
-
-    def _dispatch_loop(self):
-        code = self.code.co_code
-        instr_index = 0
-        while True:
-            jitdriver.jit_merge_point(code=code, instr_index=instr_index,
-                                      frame=self)
-            self.stack_depth = promote(self.stack_depth)
-            op = ord(code[instr_index])
-            instr_index += 1
-            if op >= HAVE_ARGUMENT:
-                low = ord(code[instr_index])
-                hi = ord(code[instr_index + 1])
-                oparg = (hi << 8) | low
-                instr_index += 2
-            else:
-                oparg = 0
-            if we_are_translated():
-                for opdesc in unrolling_opcode_descs:
-                    if op == opdesc.index:
-                        meth = getattr(self, opdesc.methodname)
-                        instr_index = meth(oparg, instr_index, code)
-                        break
-                else:
-                    raise MissingOpcode(op)
-            else:
-                meth = getattr(self, opcode_method_names[op])
-                instr_index = meth(oparg, instr_index, code)
-
-    def push(self, value):
-        self.value_stack[self.stack_depth] = value
-        self.stack_depth += 1
-
-    def pop(self):
-        sd = self.stack_depth - 1
-        assert sd >= 0
-        self.stack_depth = sd
-        val = self.value_stack[sd]
-        self.value_stack[sd] = None
-        return val
-
-    def pop_many(self, n):
-        return [self.pop() for i in range(n)]
-
-    def peek(self):
-        sd = self.stack_depth - 1
-        assert sd >= 0
-        return self.value_stack[sd]
-
-    def POP_TOP(self, _, next_instr, code):
-        self.pop()
-        return next_instr
-
-    def LOAD_FAST(self, name_index, next_instr, code):
-        assert name_index >= 0
-        self.push(self.locals[name_index])
-        return next_instr
-
-    def STORE_FAST(self, name_index, next_instr, code):
-        assert name_index >= 0
-        self.locals[name_index] = self.pop()
-        return next_instr
-
-    def LOAD_NAME(self, name_index, next_instr, code):
-        name = self.code.co_names[name_index]
-        self.push(self.locals_dict[name])
-        return next_instr
-
-    def STORE_NAME(self, name_index, next_instr, code):
-        name = self.code.co_names[name_index]
-        self.locals_dict[name] = self.pop()
-        return next_instr
-
-    def LOAD_GLOBAL(self, name_index, next_instr, code):
-        name = self.code.co_names[name_index]
-        self.push(self.globs[name])
-        return next_instr
-
-    def STORE_GLOBAL(self, name_index, next_instr, code):
-        name = self.code.co_names[name_index]
-        self.globs[name] = self.pop()
-        return next_instr
-
-    def RETURN_VALUE(self, _, next_instr, code):
-        raise Return(self.pop())
-
-    def LOAD_CONST(self, const_index, next_instr, code):
-        self.push(self.code.co_consts_w[const_index])
-        return next_instr
-
-    def BINARY_ADD(self, _, next_instr, code):
-        right = self.pop()
-        left = self.pop()
-        self.push(left.add(right))
-        return next_instr
-
-    def BINARY_SUBTRACT(self, _, next_instr, code):
-        right = self.pop()
-        left = self.pop()
-        self.push(left.sub(right))
-        return next_instr
-
-    def BINARY_AND(self, _, next_instr, code):
-        right = self.pop()
-        left = self.pop()
-        self.push(left.and_(right))
-        return next_instr        
-
-    def SETUP_LOOP(self, _, next_instr, code):
-        return next_instr
-
-    def POP_BLOCK(self, _, next_instr, code):
-        return next_instr
-
-    def JUMP_IF_FALSE(self, arg, next_instr, code):
-        w_cond = self.peek()
-        if not w_cond.is_true():
-            next_instr += arg
-        return next_instr
-
-    def POP_JUMP_IF_FALSE(self, arg, next_instr, code):
-        w_cond = self.pop()
-        if not w_cond.is_true():
-            next_instr = arg
-        return next_instr
-
-    def JUMP_FORWARD(self, arg, next_instr, code):
-        return next_instr + arg
-
-    def JUMP_ABSOLUTE(self, arg, next_instr, code):
-        jitdriver.can_enter_jit(frame=self, code=code, instr_index=arg)
-        return arg
-
-    def COMPARE_OP(self, arg, next_instr, code):
-        right = self.pop()
-        left = self.pop()
-        for num, name in unrolling_compare_dispatch_table:
-            if num == arg:
-                self.push(getattr(left, name)(right))
-        return next_instr
-
-    def MAKE_FUNCTION(self, _, next_instr, code):
-        func_code = self.pop().as_interp_class(pycode.Code)
-        func = objects.Function(func_code, self.globs)
-        self.push(func)
-        return next_instr
-
-    def CALL_FUNCTION(self, arg_count, next_instr, code):
-        args = self.pop_many(arg_count)
-        func = self.pop()
-        self.push(func.call(args))
-        return next_instr
-
-    def PRINT_ITEM(self, _, next_instr, code):
-        value = self.pop().repr().as_str()
-        os.write(1, value)
-        return next_instr
-
-    def PRINT_NEWLINE(self, _, next_instr, code):
-        os.write(1, '\n')
-        return next_instr
-
-
-items = []
-for item in unrolling_opcode_descs._items:
-    if getattr(SPLIFrame, item.methodname, None) is not None:
-        items.append(item)
-unrolling_opcode_descs = unrolling_iterable(items)

File rpython/jit/tl/spli/objects.py

-from pypy.interpreter.baseobjspace import ObjSpace, Wrappable
-from rpython.rlib.objectmodel import specialize
-
-class DumbObjSpace(ObjSpace):
-    """Implement just enough of the ObjSpace API to satisfy PyCode."""
-
-    @specialize.argtype(1)
-    def wrap(self, x):
-        if isinstance(x, int):
-            return Int(x)
-        elif isinstance(x, str):
-            return Str(x)
-        elif x is None:
-            return spli_None
-        elif isinstance(x, Wrappable):
-            return x.__spacebind__(self)
-        elif isinstance(x, SPLIObject):
-            return x # Already done.
-        else:
-            raise NotImplementedError("Wrapping %s" % x)
-
-    def new_interned_str(self, x):
-        return self.wrap(x)
-
-
-class SPLIException(Exception):
-    pass
-
-
-class W_TypeError(SPLIException):
-    pass
-
-
-class SPLIObject(object):
-
-    def add(self, other):
-        raise W_TypeError
-
-    def sub(self, other):
-        raise W_TypeError    
-
-    def and_(self, other):
-        raise W_TypeError    
-
-    def call(self, args):
-        raise W_TypeError
-
-    def cmp_lt(self, other):
-        raise W_TypeError
-
-    def cmp_gt(self, other):
-        raise W_TypeError
-
-    def cmp_eq(self, other):
-        raise W_TypeError
-
-    def cmp_ne(self, other):
-        raise W_TypeError
-
-    def cmp_ge(self, other):
-        raise W_TypeError
-
-    def cmp_le(self, other):
-        raise W_TypeError
-
-    def as_int(self):
-        raise W_TypeError
-
-    def as_str(self):
-        raise W_TypeError
-
-    def repr(self):
-        return Str("<SPLI object>")
-
-    def is_true(self):
-        raise W_TypeError
-
-    def as_interp_class(self, cls):
-        if not isinstance(self, cls):
-            raise W_TypeError
-        return self
-
-
-class Bool(SPLIObject):
-
-    def __init__(self, value):
-        self.value = value
-
-    def is_true(self):
-        return self.value
-
-    def repr(self):
-        if self.is_true():
-            name = "True"
-        else:
-            name = "False"
-        return Str(name)
-
-
-class Int(SPLIObject):
-
-    def __init__(self, value):
-        self.value = value
-
-    def add(self, other):
-        return Int(self.value + other.as_int())
-
-    def sub(self, other):
-        return Int(self.value - other.as_int())
-
-    def and_(self, other):
-        return Int(self.value & other.as_int())
-
-    def cmp_lt(self, other):
-        return Bool(self.value < other.as_int())
-
-    def as_int(self):
-        return self.value
-
-    def is_true(self):
-        return bool(self.value)
-
-    def repr(self):
-        return Str(str(self.value))
-
-
-class Str(SPLIObject):
-
-    def __init__(self, value):
-        self.value = value
-
-    def as_str(self):
-        return self.value
-
-    def add(self, other):
-        return Str(self.value + other.as_str())
-
-    def repr(self):
-        return Str("'" + self.value + "'")
-
-
-class SPLINone(SPLIObject):
-
-    def repr(self):
-        return Str('None')
-
-spli_None = SPLINone()
-
-
-class Function(SPLIObject):
-
-    def __init__(self, code, globs):
-        self.code = code
-        self.globs = globs
-
-    def call(self, args):
-        from rpython.jit.tl.spli import execution
-        return execution.run(self.code, args, None, self.globs)

File rpython/jit/tl/spli/pycode.py

-from pypy.interpreter import pycode
-from rpython.jit.tl.spli import objects
-
-
-class Code(objects.SPLIObject):
-
-    def __init__(self, argcount, nlocals, stacksize, code, consts, names):
-        """Initialize a new code object from parameters given by
-        the pypy compiler"""
-        self.co_argcount = argcount
-        self.co_nlocals = nlocals
-        self.co_stacksize = stacksize
-        self.co_code = code
-        self.co_consts_w = consts
-        self.co_names = names
-
-    @classmethod
-    def _from_code(cls, space, code, hidden_applevel=False, code_hook=None):
-        pyco = pycode.PyCode._from_code(space, code, code_hook=cls._from_code)
-        return cls(pyco.co_argcount, pyco.co_nlocals, pyco.co_stacksize,
-                   pyco.co_code, pyco.co_consts_w,
-                   [name.as_str() for name in pyco.co_names_w])

File rpython/jit/tl/spli/serializer.py

-
-""" Usage:
-serialize.py python_file func_name output_file
-"""
-
-import py
-import sys
-import types
-from rpython.jit.tl.spli.objects import Int, Str, spli_None
-from rpython.jit.tl.spli.pycode import Code
-from rpython.rlib.rstruct.runpack import runpack
-import struct
-
-FMT = 'iiii'
-int_lgt = len(struct.pack('i', 0))
-header_lgt = int_lgt * len(FMT)
-
-class NotSupportedFormat(Exception):
-    pass
-
-def serialize_str(value):
-    return struct.pack('i', len(value)) + value
-
-def unserialize_str(data, start):
-    end_lgt = start + int_lgt
-    lgt = runpack('i', data[start:end_lgt])
-    assert lgt >= 0
-    end_str = end_lgt + lgt
-    return data[end_lgt:end_str], end_str
-
-def serialize_const(const):
-    if isinstance(const, int):
-        return 'd' + struct.pack('i', const)
-    elif isinstance(const, str):
-        return 's' + serialize_str(const)
-    elif const is None:
-        return 'n'
-    elif isinstance(const, types.CodeType):
-        return 'c' + serialize(const)
-    else:
-        raise NotSupportedFormat(str(const))
-
-def unserialize_const(c, start):
-    assert start >= 0
-    if c[start] == 'd':
-        end = start + int_lgt + 1
-        intval = runpack('i', c[start + 1:end])
-        return Int(intval), end
-    elif c[start] == 's':
-        value, end = unserialize_str(c, start + 1)
-        return Str(value), end
-    elif c[start] == 'n':
-        return spli_None, start + 1
-    elif c[start] == 'c':
-        return unserialize_code(c, start + 1)
-    else:
-        raise NotSupportedFormat(c[start])
-
-def unserialize_consts(constrepr):
-    pos = int_lgt
-    consts_w = []
-    num = runpack('i', constrepr[:int_lgt])
-    for i in range(num):
-        next_const, pos = unserialize_const(constrepr, pos)
-        consts_w.append(next_const)
-    return consts_w, pos
-
-def unserialize_names(namesrepr, num):
-    pos = 0
-    names = []
-    for i in range(num):
-        name, pos = unserialize_str(namesrepr, pos)
-        names.append(name)
-    return names, pos
-
-def unserialize_code(coderepr, start=0):
-    coderepr = coderepr[start:]
-    header = coderepr[:header_lgt]
-    argcount, nlocals, stacksize, code_len = runpack(FMT, header)
-    assert code_len >= 0
-    names_pos = code_len + header_lgt
-    code = coderepr[header_lgt:names_pos]
-    num = runpack('i', coderepr[names_pos:names_pos + int_lgt])
-    names, end_names = unserialize_names(coderepr[names_pos + int_lgt:], num)
-    const_start = names_pos + int_lgt + end_names
-    consts, pos = unserialize_consts(coderepr[const_start:])
-    pos = start + const_start + pos
-    return Code(argcount, nlocals, stacksize, code, consts, names), pos
-
-# ------------------- PUBLIC API ----------------------
-
-def serialize(code):
-    header = struct.pack(FMT, code.co_argcount, code.co_nlocals,
-                         code.co_stacksize, len(code.co_code))
-    namesrepr = (struct.pack('i', len(code.co_names)) +
-                 "".join(serialize_str(name) for name in code.co_names))
-    constsrepr = (struct.pack('i', len(code.co_consts)) +
-                  "".join([serialize_const(const) for const in code.co_consts]))
-    return header + code.co_code + namesrepr + constsrepr
-
-def deserialize(data, start=0):
-    return unserialize_code(data)[0]
-
-def main(argv):
-    if len(argv) != 3:
-        print __doc__
-        sys.exit(1)
-    code_file = argv[1]
-    mod = py.path.local(code_file).read()
-    r = serialize(compile(mod, code_file, "exec"))
-    outfile = py.path.local(argv[2])
-    outfile.write(r)
-
-if __name__ == '__main__':
-    import sys
-    main(sys.argv)

File rpython/jit/tl/spli/targetspli.py

-
-""" usage: spli-c code_obj_file [i:int_arg s:s_arg ...]
-"""
-
-import sys, os
-from rpython.jit.tl.spli import execution, serializer, objects
-from rpython.rlib.streamio import open_file_as_stream
-
-
-def unwrap_arg(arg):
-    if arg.startswith('s:'):
-        return objects.Str(arg[2:])
-    elif arg.startswith('i:'):
-        return objects.Int(int(arg[2:]))
-    else:
-        raise NotImplementedError
-
-def entry_point(argv):
-    if len(argv) < 2:
-        print __doc__
-        os._exit(1)
-    args = argv[2:]
-    stream = open_file_as_stream(argv[1])
-    co = serializer.deserialize(stream.readall())
-    w_args = [unwrap_arg(args[i]) for i in range(len(args))]
-    execution.run(co, w_args)
-    return 0
-
-def target(drver, args):
-    return entry_point, None
-
-def jitpolicy(driver):
-    """Returns the JIT policy to use when translating."""
-    from rpython.jit.codewriter.policy import JitPolicy
-    return JitPolicy()
-
-if __name__ == '__main__':
-    entry_point(sys.argv)

File rpython/jit/tl/spli/test/__init__.py

Empty file removed.

File rpython/jit/tl/spli/test/test_interpreter.py

-import py
-import os
-from rpython.jit.tl.spli import execution, objects
-
-class TestSPLIInterpreter:
-
-    def eval(self, func, args=[]):
-        return execution.run_from_cpython_code(func.func_code, args)
-
-    def test_int_add(self):
-        def f():
-            return 4 + 6
-        v = self.eval(f)
-        assert isinstance(v, objects.Int)
-        assert v.value == 10
-        def f():
-            a = 4
-            return a + 6
-        assert self.eval(f).value == 10
-
-    def test_str(self):
-        def f():
-            return "Hi!"
-        v = self.eval(f)
-        assert isinstance(v, objects.Str)
-        assert v.value == "Hi!"
-        def f():
-            a = "Hello, "
-            return a + "SPLI world!"
-        v = self.eval(f)
-        assert isinstance(v, objects.Str)
-        assert v.value == "Hello, SPLI world!"
-
-    def test_comparison(self):
-        def f(i):
-            return i < 10
-
-        v = self.eval(f, [0])
-        assert isinstance(v, objects.Bool)
-        assert v.value == True
-
-    def test_while_loop(self):
-        def f():
-            i = 0
-            while i < 100:
-                i = i + 1
-            return i
-
-        v = self.eval(f)
-        assert v.value == 100
-
-    def test_invalid_adds(self):
-        def f():
-            "3" + 3
-        py.test.raises(objects.W_TypeError, self.eval, f)
-        def f():
-            3 + "3"
-        py.test.raises(objects.W_TypeError, self.eval, f)
-
-    def test_call(self):
-        code = compile("""
-def g():
-    return 4
-def f():
-    return g() + 3
-res = f()""", "<string>", "exec")
-        globs = {}
-        mod_res = execution.run_from_cpython_code(code, [], globs, globs)
-        assert mod_res is objects.spli_None
-        assert len(globs) == 3
-        assert globs["res"].as_int() == 7
-
-    def test_print(self):
-        def f(thing):
-            print thing
-        things = (
-            ("x", "'x'"),
-            (4, "4"),
-            (True, "True"),
-            (False, "False"),
-        )
-        def mock_os_write(fd, what):
-            assert fd == 1
-            buf.append(what)
-        save = os.write
-        os.write = mock_os_write
-        try:
-            for obj, res in things:
-                buf = []
-                assert self.eval(f, [obj]) is objects.spli_None
-                assert "".join(buf) == res + '\n'
-        finally:
-            os.write = save
-
-    def test_binary_op(self):
-        def f(a, b):
-            return a & b - a
-
-        v = self.eval(f, [1, 2])
-        assert v.value == f(1, 2)
-
-    def test_while_2(self):
-        def f(a, b):
-            total = 0
-            i = 0
-            while i < 100:
-                if i & 1:
-                    total = total + a
-                else:
-                    total = total + b
-                i = i + 1
-            return total
-        assert self.eval(f, [1, 10]).value == f(1, 10)

File rpython/jit/tl/spli/test/test_jit.py

-
-import py
-from rpython.jit.metainterp.test.support import JitMixin
-from rpython.jit.tl.spli import interpreter, objects, serializer
-from rpython.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper
-from rpython.jit.backend.llgraph import runner
-from rpython.rtyper.annlowlevel import llstr, hlstr
-
-class TestSPLIJit(JitMixin):
-    type_system = 'lltype'
-    CPUClass = runner.LLtypeCPU
-    
-    def interpret(self, f, args):
-        coderepr = serializer.serialize(f.func_code)
-        arg_params = ", ".join(['arg%d' % i for i in range(len(args))])
-        arg_ass = ";".join(['frame.locals[%d] = space.wrap(arg%d)' % (i, i) for
-                                 i in range(len(args))])
-        space = objects.DumbObjSpace()
-        source = py.code.Source("""
-        def bootstrap(%(arg_params)s):
-            co = serializer.deserialize(coderepr)
-            frame = interpreter.SPLIFrame(co)
-            %(arg_ass)s
-            return frame.run()
-        """ % locals())
-        d = globals().copy()
-        d['coderepr'] = coderepr
-        d['space'] = space
-        exec source.compile() in d
-        return self.meta_interp(d['bootstrap'], args, listops=True)
-    
-    def test_basic(self):
-        def f():
-            i = 0
-            while i < 20:
-                i = i + 1
-            return i
-        self.interpret(f, [])
-        self.check_resops(new_with_vtable=0)
-
-    def test_bridge(self):
-        py.test.skip('We currently cant virtualize across bridges')
-        def f(a, b):
-            total = 0
-            i = 0
-            while i < 100:
-                if i & 1:
-                    total = total + a
-                else:
-                    total = total + b
-                i = i + 1
-            return total
-
-        self.interpret(f, [1, 10])
-        self.check_resops(new_with_vtable=0)
-
-    def test_bridge_bad_case(self):
-        py.test.skip('We currently cant virtualize across bridges')
-        def f(a, b):
-            i = 0
-            while i < 100:
-                if i & 1:
-                    a = a + 1
-                else:
-                    b = b + 1
-                i = i + 1
-            return a + b
-
-        self.interpret(f, [1, 10])
-        self.check_resops(new_with_vtable=1) # XXX should eventually be 0?
-        # I think it should be either 0 or 2, 1 makes little sense
-        # If the loop after entering goes first time to the bridge, a
-        # is rewrapped again, without preserving the identity. I'm not
-        # sure how bad it is

File rpython/jit/tl/spli/test/test_serializer.py

-from rpython.jit.tl.spli.serializer import serialize, deserialize
-from rpython.jit.tl.spli import execution, pycode, objects
-
-class TestSerializer(object):
-
-    def eval(self, code, args=[]):
-        return execution.run(code, args)
-
-    def test_basic(self):
-        def f():
-            return 1
-
-        coderepr = serialize(f.func_code)
-        code = deserialize(coderepr)
-        assert code.co_nlocals == f.func_code.co_nlocals
-        assert code.co_argcount == 0
-        assert code.co_stacksize == f.func_code.co_stacksize
-        assert code.co_names == []
-        assert self.eval(code).value == 1
-
-    def test_nested_code_objects(self):
-        mod = """
-def f(): return 1
-f()"""
-        data = serialize(compile(mod, "spli", "exec"))
-        spli_code = deserialize(data)
-        assert len(spli_code.co_consts_w) == 2
-        assert isinstance(spli_code.co_consts_w[0], pycode.Code)
-        assert spli_code.co_consts_w[0].co_consts_w[0] is objects.spli_None
-        assert spli_code.co_consts_w[0].co_consts_w[1].as_int() == 1

File rpython/jit/tl/spli/test/test_translated.py

-
-from rpython.rtyper.test.test_llinterp import interpret
-from rpython.jit.tl.spli import execution, objects
-from rpython.jit.tl.spli.serializer import serialize, deserialize
-
-class TestSPLITranslated(object):
-
-    def test_one(self):
-        def f(a, b):
-            return a + b
-        data = serialize(f.func_code)
-        space = objects.DumbObjSpace()
-        def run(a, b):
-            co = deserialize(data)
-            args = []
-            args.append(space.wrap(a))
-            args.append(space.wrap(b))
-            w_res = execution.run(co, args)
-            assert isinstance(w_res, objects.Int)
-            return w_res.value
-
-        assert run(2, 3) == 5
-        res = interpret(run, [2, 3])
-        assert res == 5

File rpython/translator/tool/benchmark.py

-from pypy.tool import testit
-from rpython.tool.udir import udir
-from rpython.translator.tool.cbuild import build_cfunc
-from rpython.translator.test.test_cltrans import global_cl, make_cl_func
-
-def benchmark(func):
-    try:
-        func = func.im_func
-    except AttributeError:
-        pass
-    c_func = build_cfunc(func, dot=False)
-    if global_cl:
-        cl_func = make_cl_func(func)
-    print "generated c-func for", func.func_name
-    t1 = timeit(100, func)
-    t2 = timeit(100, c_func)
-    if global_cl:
-        t3 = timeit(100, cl_func)
-    print "cpython func       ", t1, "seconds"
-    print "pypy/pyrex/cmodule ", t2, "seconds"
-    if global_cl:
-        print "cl (experimental)  ", t3, "seconds", global_cl
-   
-def timeit(num, func, *args):
-    from time import time as now
-    start = now()
-    for i in xrange(num):
-        func(*args)
-    return now()-start
-
-if __name__ == '__main__':
-    from rpython.translator.test.snippet import sieve_of_eratosthenes
-    benchmark(sieve_of_eratosthenes)

File spli/__init__.py

Empty file added.

File spli/examples.py

+
+def f():
+    return 1
+
+print f()
+
+def adder(a, b):
+    return a + b
+
+def while_loop():
+    i = 0
+    while i < 10000000:
+        i = i + 1
+    return None
+
+while_loop()

File spli/execution.py

+from spli import interpreter, objects, pycode
+
+
+def run_from_cpython_code(co, args=[], locs=None, globs=None):
+    space = objects.DumbObjSpace()
+    pyco = pycode.Code._from_code(space, co)
+    return run(pyco, [space.wrap(arg) for arg in args], locs, globs)
+
+def run(pyco, args, locs=None, globs=None):
+    frame = interpreter.SPLIFrame(pyco, locs, globs)
+    frame.set_args(args)
+    return get_ec().execute_frame(frame)
+
+
+def get_ec():
+    ec = state.get()
+    if ec is None:
+        ec = ExecutionContext()
+        state.set(ec)
+    return ec
+
+
+class State(object):
+
+    def __init__(self):
+        self.value = None
+
+    def get(self):
+        return self.value
+
+    def set(self, new):
+        self.value = new
+
+state = State()
+
+
+class ExecutionContext(object):
+
+    def __init__(self):
+        self.framestack = []
+
+    def execute_frame(self, frame):
+        self.framestack.append(frame)
+        try:
+            return frame.run()
+        finally:
+            self.framestack.pop()

File spli/interpreter.py

+import os
+from rpython.tool import stdlib_opcode
+from spli import objects, pycode
+from rpython.rlib.unroll import unrolling_iterable
+from rpython.rlib.jit import JitDriver, promote, dont_look_inside
+from rpython.rlib.objectmodel import we_are_translated
+
+opcode_method_names = stdlib_opcode.host_bytecode_spec.method_names
+unrolling_opcode_descs = unrolling_iterable(
+    stdlib_opcode.host_bytecode_spec.ordered_opdescs)
+HAVE_ARGUMENT = stdlib_opcode.host_HAVE_ARGUMENT
+
+compare_ops = [
+    "cmp_lt",   # "<"
+    "cmp_le",   # "<="
+    "cmp_eq",   # "=="
+    "cmp_ne",   # "!="
+    "cmp_gt",   # ">"
+    "cmp_ge",   # ">="
+#    "cmp_in",
+#    "cmp_not_in",
+#    "cmp_is",
+#    "cmp_is_not",
+#    "cmp_exc_match",
+]
+unrolling_compare_dispatch_table = unrolling_iterable(
+    enumerate(compare_ops))
+
+jitdriver = JitDriver(greens = ['instr_index', 'code'],
+                      reds = ['frame'],
+                      virtualizables = ['frame'])
+
+
+class BlockUnroller(Exception):
+    pass
+
+class Return(BlockUnroller):
+
+    def __init__(self, value):
+        self.value = value
+
+class MissingOpcode(Exception):
+    pass
+
+class SPLIFrame(object):
+
+    _virtualizable2_ = ['value_stack[*]', 'locals[*]', 'stack_depth']
+
+    @dont_look_inside
+    def __init__(self, code, locs=None, globs=None):
+        self.code = code
+        self.value_stack = [None] * code.co_stacksize
+        self.locals = [None] * code.co_nlocals
+        if locs is not None:
+            self.locals_dict = locs
+        else:
+            self.locals_dict = {}
+        if globs is not None:
+            self.globs = globs
+        else:
+            self.globs = {}
+        self.stack_depth = 0
+
+    def set_args(self, args):
+        for i in range(len(args)):
+            self.locals[i] = args[i]
+
+    def run(self):
+        self.stack_depth = 0
+        try:
+            self._dispatch_loop()
+        except Return, ret:
+            return ret.value
+
+    def _dispatch_loop(self):
+        code = self.code.co_code
+        instr_index = 0
+        while True:
+            jitdriver.jit_merge_point(code=code, instr_index=instr_index,
+                                      frame=self)
+            self.stack_depth = promote(self.stack_depth)
+            op = ord(code[instr_index])
+            instr_index += 1
+            if op >= HAVE_ARGUMENT:
+                low = ord(code[instr_index])
+                hi = ord(code[instr_index + 1])
+                oparg = (hi << 8) | low
+                instr_index += 2
+            else:
+                oparg = 0
+            if we_are_translated():
+                for opdesc in unrolling_opcode_descs:
+                    if op == opdesc.index:
+                        meth = getattr(self, opdesc.methodname)
+                        instr_index = meth(oparg, instr_index, code)
+                        break
+                else:
+                    raise MissingOpcode(op)
+            else:
+                meth = getattr(self, opcode_method_names[op])
+                instr_index = meth(oparg, instr_index, code)
+
+    def push(self, value):
+        self.value_stack[self.stack_depth] = value
+        self.stack_depth += 1
+
+    def pop(self):
+        sd = self.stack_depth - 1
+        assert sd >= 0
+        self.stack_depth = sd
+        val = self.value_stack[sd]
+        self.value_stack[sd] = None
+        return val
+
+    def pop_many(self, n):
+        return [self.pop() for i in range(n)]
+
+    def peek(self):
+        sd = self.stack_depth - 1
+        assert sd >= 0
+        return self.value_stack[sd]
+
+    def POP_TOP(self, _, next_instr, code):
+        self.pop()
+        return next_instr
+
+    def LOAD_FAST(self, name_index, next_instr, code):
+        assert name_index >= 0
+        self.push(self.locals[name_index])
+        return next_instr
+
+    def STORE_FAST(self, name_index, next_instr, code):
+        assert name_index >= 0
+        self.locals[name_index] = self.pop()
+        return next_instr
+
+    def LOAD_NAME(self, name_index, next_instr, code):
+        name = self.code.co_names[name_index]
+        self.push(self.locals_dict[name])
+        return next_instr
+
+    def STORE_NAME(self, name_index, next_instr, code):
+        name = self.code.co_names[name_index]
+        self.locals_dict[name] = self.pop()
+        return next_instr
+
+    def LOAD_GLOBAL(self, name_index, next_instr, code):
+        name = self.code.co_names[name_index]
+        self.push(self.globs[name])
+        return next_instr
+
+    def STORE_GLOBAL(self, name_index, next_instr, code):
+        name = self.code.co_names[name_index]
+        self.globs[name] = self.pop()
+        return next_instr
+
+    def RETURN_VALUE(self, _, next_instr, code):
+        raise Return(self.pop())
+
+    def LOAD_CONST(self, const_index, next_instr, code):
+        self.push(self.code.co_consts_w[const_index])
+        return next_instr
+
+    def BINARY_ADD(self, _, next_instr, code):
+        right = self.pop()
+        left = self.pop()
+        self.push(left.add(right))
+        return next_instr
+
+    def BINARY_SUBTRACT(self, _, next_instr, code):
+        right = self.pop()
+        left = self.pop()
+        self.push(left.sub(right))
+        return next_instr
+
+    def BINARY_AND(self, _, next_instr, code):
+        right = self.pop()
+        left = self.pop()
+        self.push(left.and_(right))
+        return next_instr        
+
+    def SETUP_LOOP(self, _, next_instr, code):
+        return next_instr
+
+    def POP_BLOCK(self, _, next_instr, code):
+        return next_instr
+
+    def JUMP_IF_FALSE(self, arg, next_instr, code):
+        w_cond = self.peek()
+        if not w_cond.is_true():
+            next_instr += arg
+        return next_instr
+
+    def POP_JUMP_IF_FALSE(self, arg, next_instr, code):
+        w_cond = self.pop()
+        if not w_cond.is_true():
+            next_instr = arg
+        return next_instr
+
+    def JUMP_FORWARD(self, arg, next_instr, code):
+        return next_instr + arg
+
+    def JUMP_ABSOLUTE(self, arg, next_instr, code):
+        jitdriver.can_enter_jit(frame=self, code=code, instr_index=arg)
+        return arg
+
+    def COMPARE_OP(self, arg, next_instr, code):
+        right = self.pop()
+        left = self.pop()
+        for num, name in unrolling_compare_dispatch_table:
+            if num == arg:
+                self.push(getattr(left, name)(right))
+        return next_instr
+
+    def MAKE_FUNCTION(self, _, next_instr, code):
+        func_code = self.pop().as_interp_class(pycode.Code)
+        func = objects.Function(func_code, self.globs)
+        self.push(func)
+        return next_instr
+
+    def CALL_FUNCTION(self, arg_count, next_instr, code):
+        args = self.pop_many(arg_count)
+        func = self.pop()
+        self.push(func.call(args))
+        return next_instr
+
+    def PRINT_ITEM(self, _, next_instr, code):
+        value = self.pop().repr().as_str()
+        os.write(1, value)
+        return next_instr
+
+    def PRINT_NEWLINE(self, _, next_instr, code):
+        os.write(1, '\n')
+        return next_instr
+
+
+items = []
+for item in unrolling_opcode_descs._items:
+    if getattr(SPLIFrame, item.methodname, None) is not None:
+        items.append(item)
+unrolling_opcode_descs = unrolling_iterable(items)

File spli/objects.py

+from pypy.interpreter.baseobjspace import ObjSpace, Wrappable
+from rpython.rlib.objectmodel import specialize
+
+class DumbObjSpace(ObjSpace):
+    """Implement just enough of the ObjSpace API to satisfy PyCode."""
+
+    @specialize.argtype(1)
+    def wrap(self, x):
+        if isinstance(x, int):
+            return Int(x)
+        elif isinstance(x, str):
+            return Str(x)
+        elif x is None:
+            return spli_None
+        elif isinstance(x, Wrappable):
+            return x.__spacebind__(self)
+        elif isinstance(x, SPLIObject):
+            return x # Already done.
+        else:
+            raise NotImplementedError("Wrapping %s" % x)
+
+    def new_interned_str(self, x):
+        return self.wrap(x)
+
+
+class SPLIException(Exception):
+    pass
+
+
+class W_TypeError(SPLIException):
+    pass
+
+
+class SPLIObject(object):
+
+    def add(self, other):
+        raise W_TypeError
+
+    def sub(self, other):
+        raise W_TypeError    
+
+    def and_(self, other):
+        raise W_TypeError    
+
+    def call(self, args):
+        raise W_TypeError
+
+    def cmp_lt(self, other):
+        raise W_TypeError
+
+    def cmp_gt(self, other):
+        raise W_TypeError
+
+    def cmp_eq(self, other):
+        raise W_TypeError
+
+    def cmp_ne(self, other):
+        raise W_TypeError
+
+    def cmp_ge(self, other):
+        raise W_TypeError
+
+    def cmp_le(self, other):
+        raise W_TypeError
+
+    def as_int(self):
+        raise W_TypeError
+
+    def as_str(self):
+        raise W_TypeError
+
+    def repr(self):
+        return Str("<SPLI object>")
+
+    def is_true(self):
+        raise W_TypeError
+
+    def as_interp_class(self, cls):
+        if not isinstance(self, cls):
+            raise W_TypeError
+        return self
+
+
+class Bool(SPLIObject):
+
+    def __init__(self, value):
+        self.value = value
+
+    def is_true(self):
+        return self.value
+
+    def repr(self):
+        if self.is_true():
+            name = "True"
+        else:
+            name = "False"
+        return Str(name)
+
+
+class Int(SPLIObject):
+
+    def __init__(self, value):
+        self.value = value
+
+    def add(self, other):
+        return Int(self.value + other.as_int())
+
+    def sub(self, other):
+        return Int(self.value - other.as_int())
+
+    def and_(self, other):
+        return Int(self.value & other.as_int())
+
+    def cmp_lt(self, other):
+        return Bool(self.value < other.as_int())
+
+    def as_int(self):
+        return self.value
+
+    def is_true(self):
+        return bool(self.value)
+
+    def repr(self):
+        return Str(str(self.value))
+
+
+class Str(SPLIObject):
+
+    def __init__(self, value):
+        self.value = value
+
+    def as_str(self):
+        return self.value
+
+    def add(self, other):
+        return Str(self.value + other.as_str())
+
+    def repr(self):
+        return Str("'" + self.value + "'")
+
+
+class SPLINone(SPLIObject):
+
+    def repr(self):
+        return Str('None')
+
+spli_None = SPLINone()
+
+
+class Function(SPLIObject):
+
+    def __init__(self, code, globs):
+        self.code = code
+        self.globs = globs
+
+    def call(self, args):
+        from spli import execution
+        return execution.run(self.code, args, None, self.globs)

File spli/pycode.py

+from pypy.interpreter import pycode
+from spli import objects
+
+
+class Code(objects.SPLIObject):
+
+    def __init__(self, argcount, nlocals, stacksize, code, consts, names):
+        """Initialize a new code object from parameters given by
+        the pypy compiler"""
+        self.co_argcount = argcount
+        self.co_nlocals = nlocals
+        self.co_stacksize = stacksize
+        self.co_code = code
+        self.co_consts_w = consts
+        self.co_names = names
+
+    @classmethod
+    def _from_code(cls, space, code, hidden_applevel=False, code_hook=None):
+        pyco = pycode.PyCode._from_code(space, code, code_hook=cls._from_code)
+        return cls(pyco.co_argcount, pyco.co_nlocals, pyco.co_stacksize,
+                   pyco.co_code, pyco.co_consts_w,
+                   [name.as_str() for name in pyco.co_names_w])

File spli/serializer.py

+
+""" Usage:
+serialize.py python_file func_name output_file
+"""
+
+import py
+import sys
+import types
+from spli.objects import Int, Str, spli_None
+from spli.pycode import Code
+from rpython.rlib.rstruct.runpack import runpack
+import struct
+
+FMT = 'iiii'
+int_lgt = len(struct.pack('i', 0))
+header_lgt = int_lgt * len(FMT)
+
+class NotSupportedFormat(Exception):
+    pass
+
+def serialize_str(value):
+    return struct.pack('i', len(value)) + value
+
+def unserialize_str(data, start):
+    end_lgt = start + int_lgt
+    lgt = runpack('i', data[start:end_lgt])
+    assert lgt >= 0
+    end_str = end_lgt + lgt
+    return data[end_lgt:end_str], end_str
+
+def serialize_const(const):
+    if isinstance(const, int):
+        return 'd' + struct.pack('i', const)
+    elif isinstance(const, str):
+        return 's' + serialize_str(const)
+    elif const is None:
+        return 'n'
+    elif isinstance(const, types.CodeType):
+        return 'c' + serialize(const)
+    else:
+        raise NotSupportedFormat(str(const))
+
+def unserialize_const(c, start):
+    assert start >= 0
+    if c[start] == 'd':
+        end = start + int_lgt + 1
+        intval = runpack('i', c[start + 1:end])
+        return Int(intval), end
+    elif c[start] == 's':
+        value, end = unserialize_str(c, start + 1)
+        return Str(value), end
+    elif c[start] == 'n':
+        return spli_None, start + 1
+    elif c[start] == 'c':
+        return unserialize_code(c, start + 1)
+    else:
+        raise NotSupportedFormat(c[start])
+
+def unserialize_consts(constrepr):
+    pos = int_lgt
+    consts_w = []
+    num = runpack('i', constrepr[:int_lgt])
+    for i in range(num):
+        next_const, pos = unserialize_const(constrepr, pos)
+        consts_w.append(next_const)
+    return consts_w, pos
+
+def unserialize_names(namesrepr, num):
+    pos = 0
+    names = []
+    for i in range(num):
+        name, pos = unserialize_str(namesrepr, pos)
+        names.append(name)
+    return names, pos
+
+def unserialize_code(coderepr, start=0):
+    coderepr = coderepr[start:]
+    header = coderepr[:header_lgt]
+    argcount, nlocals, stacksize, code_len = runpack(FMT, header)
+    assert code_len >= 0
+    names_pos = code_len + header_lgt
+    code = coderepr[header_lgt:names_pos]
+    num = runpack('i', coderepr[names_pos:names_pos + int_lgt])
+    names, end_names = unserialize_names(coderepr[names_pos + int_lgt:], num)
+    const_start = names_pos + int_lgt + end_names
+    consts, pos = unserialize_consts(coderepr[const_start:])
+    pos = start + const_start + pos
+    return Code(argcount, nlocals, stacksize, code, consts, names), pos
+
+# ------------------- PUBLIC API ----------------------
+
+def serialize(code):
+    header = struct.pack(FMT, code.co_argcount, code.co_nlocals,
+                         code.co_stacksize, len(code.co_code))
+    namesrepr = (struct.pack('i', len(code.co_names)) +
+                 "".join(serialize_str(name) for name in code.co_names))
+    constsrepr = (struct.pack('i', len(code.co_consts)) +
+                  "".join([serialize_const(const) for const in code.co_consts]))
+    return header + code.co_code + namesrepr + constsrepr
+
+def deserialize(data, start=0):
+    return unserialize_code(data)[0]
+
+def main(argv):
+    if len(argv) != 3:
+        print __doc__
+        sys.exit(1)
+    code_file = argv[1]
+    mod = py.path.local(code_file).read()
+    r = serialize(compile(mod, code_file, "exec"))
+    outfile = py.path.local(argv[2])
+    outfile.write(r)
+
+if __name__ == '__main__':
+    import sys
+    main(sys.argv)

File spli/targetspli.py

+
+""" usage: spli-c code_obj_file [i:int_arg s:s_arg ...]
+"""
+
+import sys, os
+from spli import execution, serializer, objects
+from rpython.rlib.streamio import open_file_as_stream
+
+
+def unwrap_arg(arg):
+    if arg.startswith('s:'):
+        return objects.Str(arg[2:])
+    elif arg.startswith('i:'):
+        return objects.Int(int(arg[2:]))
+    else:
+        raise NotImplementedError
+
+def entry_point(argv):
+    if len(argv) < 2:
+        print __doc__
+        os._exit(1)
+    args = argv[2:]
+    stream = open_file_as_stream(argv[1])
+    co = serializer.deserialize(stream.readall())
+    w_args = [unwrap_arg(args[i]) for i in range(len(args))]
+    execution.run(co, w_args)
+    return 0
+
+def target(drver, args):
+    return entry_point, None
+
+def jitpolicy(driver):
+    """Returns the JIT policy to use when translating."""
+    from rpython.jit.codewriter.policy import JitPolicy
+    return JitPolicy()
+
+if __name__ == '__main__':
+    entry_point(sys.argv)

File spli/test/__init__.py

Empty file added.

File spli/test/test_interpreter.py

+import py
+import os
+from spli import execution, objects
+
+class TestSPLIInterpreter:
+
+    def eval(self, func, args=[]):
+        return execution.run_from_cpython_code(func.func_code, args)
+
+    def test_int_add(self):
+        def f():
+            return 4 + 6
+        v = self.eval(f)
+        assert isinstance(v, objects.Int)
+        assert v.value == 10
+        def f():
+            a = 4
+            return a + 6
+        assert self.eval(f).value == 10
+
+    def test_str(self):
+        def f():
+            return "Hi!"
+        v = self.eval(f)
+        assert isinstance(v, objects.Str)
+        assert v.value == "Hi!"
+        def f():
+            a = "Hello, "
+            return a + "SPLI world!"
+        v = self.eval(f)
+        assert isinstance(v, objects.Str)
+        assert v.value == "Hello, SPLI world!"
+
+    def test_comparison(self):
+        def f(i):
+            return i < 10
+
+        v = self.eval(f, [0])
+        assert isinstance(v, objects.Bool)
+        assert v.value == True
+
+    def test_while_loop(self):
+        def f():
+            i = 0
+            while i < 100:
+                i = i + 1
+            return i
+
+        v = self.eval(f)
+        assert v.value == 100
+
+    def test_invalid_adds(self):
+        def f():
+            "3" + 3
+        py.test.raises(objects.W_TypeError, self.eval, f)
+        def f():
+            3 + "3"
+        py.test.raises(objects.W_TypeError, self.eval, f)
+
+    def test_call(self):
+        code = compile("""
+def g():
+    return 4
+def f():
+    return g() + 3
+res = f()""", "<string>", "exec")
+        globs = {}
+        mod_res = execution.run_from_cpython_code(code, [], globs, globs)
+        assert mod_res is objects.spli_None
+        assert len(globs) == 3
+        assert globs["res"].as_int() == 7
+
+    def test_print(self):
+        def f(thing):
+            print thing
+        things = (
+            ("x", "'x'"),
+            (4, "4"),
+            (True, "True"),
+            (False, "False"),
+        )
+        def mock_os_write(fd, what):
+            assert fd == 1
+            buf.append(what)
+        save = os.write
+        os.write = mock_os_write
+        try:
+            for obj, res in things:
+                buf = []
+                assert self.eval(f, [obj]) is objects.spli_None
+                assert "".join(buf) == res + '\n'
+        finally:
+            os.write = save
+
+    def test_binary_op(self):
+        def f(a, b):
+            return a & b - a
+
+        v = self.eval(f, [1, 2])
+        assert v.value == f(1, 2)
+
+    def test_while_2(self):
+        def f(a, b):
+            total = 0
+            i = 0
+            while i < 100:
+                if i & 1:
+                    total = total + a
+                else:
+                    total = total + b
+                i = i + 1
+            return total
+        assert self.eval(f, [1, 10]).value == f(1, 10)

File spli/test/test_jit.py

+
+import py
+from rpython.jit.metainterp.test.support import JitMixin
+from spli import interpreter, objects, serializer
+from rpython.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper
+from rpython.jit.backend.llgraph import runner
+from rpython.rtyper.annlowlevel import llstr, hlstr
+
+class TestSPLIJit(JitMixin):
+    type_system = 'lltype'
+    CPUClass = runner.LLtypeCPU
+    
+    def interpret(self, f, args):
+        coderepr = serializer.serialize(f.func_code)
+        arg_params = ", ".join(['arg%d' % i for i in range(len(args))])
+        arg_ass = ";".join(['frame.locals[%d] = space.wrap(arg%d)' % (i, i) for
+                                 i in range(len(args))])
+        space = objects.DumbObjSpace()
+        source = py.code.Source("""
+        def bootstrap(%(arg_params)s):
+            co = serializer.deserialize(coderepr)
+            frame = interpreter.SPLIFrame(co)
+            %(arg_ass)s
+            return frame.run()
+        """ % locals())
+        d = globals().copy()
+        d['coderepr'] = coderepr
+        d['space'] = space
+        exec source.compile() in d
+        return self.meta_interp(d['bootstrap'], args, listops=True)
+    
+    def test_basic(self):
+        def f():
+            i = 0
+            while i < 20:
+                i = i + 1
+            return i
+        self.interpret(f, [])
+        self.check_resops(new_with_vtable=0)
+
+    def test_bridge(self):
+        py.test.skip('We currently cant virtualize across bridges')
+        def f(a, b):
+            total = 0
+            i = 0
+            while i < 100:
+                if i & 1:
+                    total = total + a
+                else:
+                    total = total + b
+                i = i + 1
+            return total
+
+        self.interpret(f, [1, 10])
+        self.check_resops(new_with_vtable=0)
+
+    def test_bridge_bad_case(self):
+        py.test.skip('We currently cant virtualize across bridges')
+        def f(a, b):
+            i = 0
+            while i < 100:
+                if i & 1:
+                    a = a + 1
+                else:
+                    b = b + 1
+                i = i + 1
+            return a + b
+
+        self.interpret(f, [1, 10])
+        self.check_resops(new_with_vtable=1) # XXX should eventually be 0?
+        # I think it should be either 0 or 2, 1 makes little sense
+        # If the loop after entering goes first time to the bridge, a
+        # is rewrapped again, without preserving the identity. I'm not
+        # sure how bad it is

File spli/test/test_serializer.py

+from spli.serializer import serialize, deserialize
+from spli import execution, pycode, objects
+
+class TestSerializer(object):
+
+    def eval(self, code, args=[]):
+        return execution.run(code, args)
+
+    def test_basic(self):
+        def f():
+            return 1
+
+        coderepr = serialize(f.func_code)
+        code = deserialize(coderepr)
+        assert code.co_nlocals == f.func_code.co_nlocals
+        assert code.co_argcount == 0
+        assert code.co_stacksize == f.func_code.co_stacksize
+        assert code.co_names == []
+        assert self.eval(code).value == 1
+
+    def test_nested_code_objects(self):
+        mod = """
+def f(): return 1
+f()"""
+        data = serialize(compile(mod, "spli", "exec"))
+        spli_code = deserialize(data)
+        assert len(spli_code.co_consts_w) == 2
+        assert isinstance(spli_code.co_consts_w[0], pycode.Code)
+        assert spli_code.co_consts_w[0].co_consts_w[0] is objects.spli_None
+        assert spli_code.co_consts_w[0].co_consts_w[1].as_int() == 1

File spli/test/test_translated.py

+
+from rpython.rtyper.test.test_llinterp import interpret
+from spli import execution, objects
+from spli.serializer import serialize, deserialize
+
+class TestSPLITranslated(object):
+
+    def test_one(self):
+        def f(a, b):
+            return a + b
+        data = serialize(f.func_code)
+        space = objects.DumbObjSpace()
+        def run(a, b):
+            co = deserialize(data)
+            args = []
+            args.append(space.wrap(a))
+            args.append(space.wrap(b))
+            w_res = execution.run(co, args)
+            assert isinstance(w_res, objects.Int)
+            return w_res.value
+
+        assert run(2, 3) == 5
+        res = interpret(run, [2, 3])
+        assert res == 5