[pypy-commit] pypy jit-short_from_state: keep track of array/str/unicode length and guard for them to make getitems safe in short preamble
hakanardo
noreply at buildbot.pypy.org
Wed Jul 20 10:19:41 CEST 2011
Author: Hakan Ardo <hakan at debian.org>
Branch: jit-short_from_state
Changeset: r45766:3f1e8b5dd3b0
Date: 2011-07-20 09:38 +0200
http://bitbucket.org/pypy/pypy/changeset/3f1e8b5dd3b0/
Log: keep track of array/str/unicode length and guard for them to make
getitems safe in short preamble
diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py
--- a/pypy/jit/metainterp/optimizeopt/heap.py
+++ b/pypy/jit/metainterp/optimizeopt/heap.py
@@ -3,7 +3,7 @@
from pypy.jit.metainterp.resoperation import rop, ResOperation
from pypy.rlib.objectmodel import we_are_translated
from pypy.jit.metainterp.jitexc import JitException
-from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
+from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, MODE_ARRAY
from pypy.jit.metainterp.history import ConstInt, Const
@@ -407,6 +407,7 @@
indexvalue = self.getvalue(op.getarg(1))
cf = None
if indexvalue.is_constant():
+ arrayvalue.make_len_gt(MODE_ARRAY, op.getdescr(), indexvalue.box.getint())
# use the cache on (arraydescr, index), which is a constant
cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint())
fieldvalue = cf.getfield_from_cache(self, arrayvalue)
@@ -434,6 +435,8 @@
#
indexvalue = self.getvalue(op.getarg(1))
if indexvalue.is_constant():
+ arrayvalue = self.getvalue(op.getarg(0))
+ arrayvalue.make_len_gt(MODE_ARRAY, op.getdescr(), indexvalue.box.getint())
# use the cache on (arraydescr, index), which is a constant
cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint())
cf.do_setfield(self, op)
diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py
--- a/pypy/jit/metainterp/optimizeopt/intbounds.py
+++ b/pypy/jit/metainterp/optimizeopt/intbounds.py
@@ -1,4 +1,5 @@
-from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0
+from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0, \
+ MODE_ARRAY, MODE_STR, MODE_UNICODE
from pypy.jit.metainterp.optimizeopt.util import _findall
from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded,
IntLowerBound, IntUpperBound)
@@ -285,10 +286,24 @@
def optimize_ARRAYLEN_GC(self, op):
self.emit_operation(op)
- v1 = self.getvalue(op.result)
- v1.intbound.make_ge(IntLowerBound(0))
+ array = self.getvalue(op.getarg(0))
+ result = self.getvalue(op.result)
+ array.make_len_gt(MODE_ARRAY, op.getdescr(), -1)
+ result.intbound = array.lenbound[2]
- optimize_STRLEN = optimize_UNICODELEN = optimize_ARRAYLEN_GC
+ def optimize_STRLEN(self, op):
+ self.emit_operation(op)
+ array = self.getvalue(op.getarg(0))
+ result = self.getvalue(op.result)
+ array.make_len_gt(MODE_STR, op.getdescr(), -1)
+ result.intbound = array.lenbound[2]
+
+ def optimize_UNICODELEN(self, op):
+ self.emit_operation(op)
+ array = self.getvalue(op.getarg(0))
+ result = self.getvalue(op.result)
+ array.make_len_gt(MODE_UNICODE, op.getdescr(), -1)
+ result.intbound = array.lenbound[2]
def optimize_STRGETITEM(self, op):
self.emit_operation(op)
diff --git a/pypy/jit/metainterp/optimizeopt/intutils.py b/pypy/jit/metainterp/optimizeopt/intutils.py
--- a/pypy/jit/metainterp/optimizeopt/intutils.py
+++ b/pypy/jit/metainterp/optimizeopt/intutils.py
@@ -1,4 +1,9 @@
from pypy.rlib.rarithmetic import ovfcheck, ovfcheck_lshift, LONG_BIT
+from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.history import BoxInt, ConstInt
+import sys
+MAXINT = sys.maxint
+MININT = -sys.maxint - 1
class IntBound(object):
_attrs_ = ('has_upper', 'has_lower', 'upper', 'lower')
@@ -225,6 +230,23 @@
res.has_upper = self.has_upper
return res
+ def make_guards(self, box, guards):
+ if self.has_lower and self.lower > MININT:
+ bound = self.lower
+ res = BoxInt()
+ op = ResOperation(rop.INT_GE, [box, ConstInt(bound)], res)
+ guards.append(op)
+ op = ResOperation(rop.GUARD_TRUE, [res], None)
+ guards.append(op)
+ if self.has_upper and self.upper < MAXINT:
+ bound = self.upper
+ res = BoxInt()
+ op = ResOperation(rop.INT_LE, [box, ConstInt(bound)], res)
+ guards.append(op)
+ op = ResOperation(rop.GUARD_TRUE, [res], None)
+ guards.append(op)
+
+
class IntUpperBound(IntBound):
def __init__(self, upper):
self.has_upper = True
diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -12,26 +12,29 @@
from pypy.rpython.lltypesystem import lltype
from pypy.jit.metainterp.history import AbstractDescr, make_hashable_int
from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded, \
- ImmutableIntUnbounded
+ ImmutableIntUnbounded, \
+ IntLowerBound, MININT, MAXINT
from pypy.tool.pairtype import extendabletype
+from pypy.rlib.debug import debug_start, debug_stop, debug_print
LEVEL_UNKNOWN = '\x00'
LEVEL_NONNULL = '\x01'
LEVEL_KNOWNCLASS = '\x02' # might also mean KNOWNARRAYDESCR, for arrays
LEVEL_CONSTANT = '\x03'
-import sys
-MAXINT = sys.maxint
-MININT = -sys.maxint - 1
+MODE_ARRAY = '\x00'
+MODE_STR = '\x01'
+MODE_UNICODE = '\x02'
class OptValue(object):
__metaclass__ = extendabletype
- _attrs_ = ('box', 'known_class', 'last_guard_index', 'level', 'intbound')
+ _attrs_ = ('box', 'known_class', 'last_guard_index', 'level', 'intbound', 'lenbound')
last_guard_index = -1
level = LEVEL_UNKNOWN
known_class = None
intbound = ImmutableIntUnbounded()
+ lenbound = None
def __init__(self, box, level=None, known_class=None, intbound=None):
self.box = box
@@ -50,6 +53,14 @@
self.make_constant(box)
# invariant: box is a Const if and only if level == LEVEL_CONSTANT
+ def make_len_gt(self, mode, descr, val):
+ if self.lenbound:
+ assert self.lenbound[0] == mode
+ assert self.lenbound[1] == descr
+ self.lenbound[2].make_gt(IntBound(val, val))
+ else:
+ self.lenbound = (mode, descr, IntLowerBound(val + 1))
+
def make_guards(self, box):
guards = []
if self.level == LEVEL_CONSTANT:
@@ -64,20 +75,21 @@
if self.level == LEVEL_NONNULL:
op = ResOperation(rop.GUARD_NONNULL, [box], None)
guards.append(op)
- if self.intbound.has_lower and self.intbound.lower > MININT:
- bound = self.intbound.lower
- res = BoxInt()
- op = ResOperation(rop.INT_GE, [box, ConstInt(bound)], res)
+ self.intbound.make_guards(box, guards)
+ if self.lenbound:
+ lenbox = BoxInt()
+ if self.lenbound[0] == MODE_ARRAY:
+ op = ResOperation(rop.ARRAYLEN_GC, [box], lenbox, self.lenbound[1])
+ elif self.lenbound[0] == MODE_STR:
+ op = ResOperation(rop.STRLEN, [box], lenbox, self.lenbound[1])
+ elif self.lenbound[0] == MODE_UNICODE:
+ op = ResOperation(rop.UNICODELEN, [box], lenbox, self.lenbound[1])
+ else:
+ debug_print("Unknown lenbound mode")
+ assert False
guards.append(op)
- op = ResOperation(rop.GUARD_TRUE, [res], None)
- guards.append(op)
- if self.intbound.has_upper and self.intbound.upper < MAXINT:
- bound = self.intbound.upper
- res = BoxInt()
- op = ResOperation(rop.INT_LE, [box, ConstInt(bound)], res)
- guards.append(op)
- op = ResOperation(rop.GUARD_TRUE, [res], None)
- guards.append(op)
+ self.lenbound[2].make_guards(lenbox, guards)
+
return guards
def force_box(self):
@@ -428,6 +440,11 @@
def produce_potential_short_preamble_ops(self, sb):
for op in self.emitted_pure_operations:
+ if op.getopnum() == rop.GETARRAYITEM_GC_PURE or \
+ op.getopnum() == rop.STRGETITEM or \
+ op.getopnum() == rop.UNICODEGETITEM:
+ if not self.getvalue(op.getarg(1)).is_constant():
+ continue
sb.add_potential(op)
for opt in self.optimizations:
opt.produce_potential_short_preamble_ops(sb)
@@ -676,6 +693,30 @@
def optimize_DEBUG_MERGE_POINT(self, op):
self.emit_operation(op)
+ def optimize_GETARRAYITEM_GC_PURE(self, op):
+ indexvalue = self.getvalue(op.getarg(1))
+ if indexvalue.is_constant():
+ arrayvalue = self.getvalue(op.getarg(0))
+ arrayvalue.make_len_gt(MODE_ARRAY, op.getdescr(), indexvalue.box.getint())
+ self.optimize_default(op)
+
+ def optimize_STRGETITEM(self, op):
+ indexvalue = self.getvalue(op.getarg(1))
+ if indexvalue.is_constant():
+ arrayvalue = self.getvalue(op.getarg(0))
+ arrayvalue.make_len_gt(MODE_STR, op.getdescr(), indexvalue.box.getint())
+ self.optimize_default(op)
+
+ def optimize_UNICODEGETITEM(self, op):
+ indexvalue = self.getvalue(op.getarg(1))
+ if indexvalue.is_constant():
+ arrayvalue = self.getvalue(op.getarg(0))
+ arrayvalue.make_len_gt(MODE_UNICODE, op.getdescr(), indexvalue.box.getint())
+ self.optimize_default(op)
+
+
+
+
optimize_ops = _findall(Optimizer, 'optimize_')
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -6467,6 +6467,22 @@
"""
self.optimize_loop(ops, expected)
+ def test_loopinvariant_strlen_with_bound(self):
+ ops = """
+ [p9]
+ i843 = strlen(p9)
+ i1 = int_gt(i843, 7)
+ guard_true(i1) []
+ call(i843, descr=nonwritedescr)
+ jump(p9)
+ """
+ expected = """
+ [p9, i2]
+ call(i2, descr=nonwritedescr)
+ jump(p9, i2)
+ """
+ self.optimize_loop(ops, expected)
+
def test_loopinvariant_strgetitem(self):
ops = """
[p9, i1]
@@ -6474,12 +6490,7 @@
call(i843, descr=nonwritedescr)
jump(p9, i1)
"""
- expected = """
- [p9, i1, i2]
- call(i2, descr=nonwritedescr)
- jump(p9, i1, i2)
- """
- self.optimize_loop(ops, expected)
+ self.optimize_loop(ops, ops)
def test_loopinvariant_unicodelen(self):
ops = """
@@ -6502,12 +6513,7 @@
call(i843, descr=nonwritedescr)
jump(p9, i1)
"""
- expected = """
- [p9, i1, i2]
- call(i2, descr=nonwritedescr)
- jump(p9, i1, i2)
- """
- self.optimize_loop(ops, expected)
+ self.optimize_loop(ops, ops)
def test_loopinvariant_arraylen(self):
ops = """
@@ -6525,21 +6531,26 @@
def test_loopinvariant_getarrayitem(self):
ops = """
- [p1]
+ [p0]
+ p1 = getfield_gc(p0, descr=nextdescr)
p2 = getarrayitem_gc(p1, 7, descr=<GcPtrArrayDescr>)
call(p2, descr=nonwritedescr)
- jump(p1)
+ jump(p0)
"""
short = """
- [p1]
+ [p0]
+ p1 = getfield_gc(p0, descr=nextdescr)
+ guard_nonnull(p1) []
i1 = arraylen_gc(p1)
+ i2 = int_ge(i1, 8)
+ guard_true(i2) []
p2 = getarrayitem_gc(p1, 7, descr=<GcPtrArrayDescr>)
- jump(p1, p2)
- """
- expected = """
- [p1, p2]
+ jump(p0, p2)
+ """
+ expected = """
+ [p0, p2]
call(p2, descr=nonwritedescr)
- jump(p1, p2)
+ jump(p0, p2)
"""
self.optimize_loop(ops, expected, expected_short=short)
@@ -6555,6 +6566,115 @@
"""
self.optimize_loop(ops, expected)
+ def test_arraylen_bound(self):
+ ops = """
+ [p1, i]
+ p2 = getarrayitem_gc(p1, 7, descr=<GcPtrArrayDescr>)
+ i1 = arraylen_gc(p1)
+ i2 = int_ge(i1, 8)
+ guard_true(i2) []
+ jump(p2, i2)
+ """
+ expected = """
+ [p1]
+ p2 = getarrayitem_gc(p1, 7, descr=<GcPtrArrayDescr>)
+ i1 = arraylen_gc(p1)
+ jump(p2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_loopinvariant_getarrayitem_gc_pure(self):
+ ops = """
+ [p9, i1]
+ i843 = getarrayitem_gc_pure(p9, i1)
+ call(i843, descr=nonwritedescr)
+ jump(p9, i1)
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_loopinvariant_constant_getarrayitem_pure(self):
+ ops = """
+ [p0]
+ p1 = getfield_gc(p0, descr=nextdescr)
+ p2 = getarrayitem_gc_pure(p1, 7, descr=<GcPtrArrayDescr>)
+ call(p2, descr=nonwritedescr)
+ jump(p0)
+ """
+ short = """
+ [p0]
+ p1 = getfield_gc(p0, descr=nextdescr)
+ guard_nonnull(p1) []
+ i1 = arraylen_gc(p1)
+ i2 = int_ge(i1, 8)
+ guard_true(i2) []
+ p2 = getarrayitem_gc_pure(p1, 7, descr=<GcPtrArrayDescr>)
+ jump(p0, p2)
+ """
+ expected = """
+ [p0, p2]
+ call(p2, descr=nonwritedescr)
+ jump(p0, p2)
+ """
+ self.optimize_loop(ops, expected, expected_short=short)
+
+
+ def test_loopinvariant_constant_strgetitem(self):
+ ops = """
+ [p0]
+ p1 = getfield_gc(p0, descr=nextdescr)
+ p2 = strgetitem(p1, 7)
+ call(p2, descr=nonwritedescr)
+ jump(p0)
+ """
+ short = """
+ [p0]
+ p1 = getfield_gc(p0, descr=nextdescr)
+ guard_nonnull(p1) []
+ i1 = strlen(p1)
+ i2 = int_ge(i1, 8)
+ guard_true(i2) []
+ p2 = strgetitem(p1, 7, descr=<GcPtrArrayDescr>)
+ i8 = int_ge(p2, 0)
+ guard_true(i8) []
+ i9 = int_le(p2, 255)
+ guard_true(i9) []
+ jump(p0, p2)
+ """
+ expected = """
+ [p0, p2]
+ call(p2, descr=nonwritedescr)
+ jump(p0, p2)
+ """
+ self.optimize_loop(ops, expected, expected_short=short)
+
+ def test_loopinvariant_constant_unicodegetitem(self):
+ ops = """
+ [p0]
+ p1 = getfield_gc(p0, descr=nextdescr)
+ p2 = unicodegetitem(p1, 7)
+ call(p2, descr=nonwritedescr)
+ jump(p0)
+ """
+ short = """
+ [p0]
+ p1 = getfield_gc(p0, descr=nextdescr)
+ guard_nonnull(p1) []
+ i1 = unicodelen(p1)
+ i2 = int_ge(i1, 8)
+ guard_true(i2) []
+ p2 = unicodegetitem(p1, 7, descr=<GcPtrArrayDescr>)
+ i8 = int_ge(p2, 0)
+ guard_true(i8) []
+ jump(p0, p2)
+ """
+ expected = """
+ [p0, p2]
+ call(p2, descr=nonwritedescr)
+ jump(p0, p2)
+ """
+ self.optimize_loop(ops, expected, expected_short=short)
+
+
class TestLLtype(OptimizeOptTest, LLtypeMixin):
pass
diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py
--- a/pypy/jit/metainterp/optimizeopt/unroll.py
+++ b/pypy/jit/metainterp/optimizeopt/unroll.py
@@ -247,6 +247,7 @@
initial_inputargs_len = len(inputargs)
self.inliner = Inliner(loop.inputargs, jump_args)
+
short = self.inline(inputargs, self.cloned_operations,
loop.inputargs, short_inputargs,
virtual_state)
diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py
--- a/pypy/jit/metainterp/optimizeopt/virtualstate.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py
@@ -201,6 +201,7 @@
else:
self.constbox = None
self.position_in_notvirtuals = -1
+ self.lenbound = value.lenbound
def generalization_of(self, other, renum, bad):
# XXX This will always retrace instead of forcing anything which
@@ -235,12 +236,26 @@
bad[self] = True
bad[other] = True
return False
+ if self.lenbound and other.lenbound:
+ if self.lenbound[0] != other.lenbound[0] or \
+ self.lenbound[1] != other.lenbound[1] or \
+ not self.lenbound[2].contains_bound(other.lenbound[2]):
+ bad[self] = True
+ bad[other] = True
+ return False
+ elif self.lenbound or other.lenbound:
+ bad[self] = True
+ bad[other] = True
+ return False
return True
def _generate_guards(self, other, box, cpu, extra_guards):
if not isinstance(other, NotVirtualStateInfo):
raise InvalidLoop
+ if self.lenbound or other.lenbound:
+ raise InvalidLoop
+
if self.level == LEVEL_KNOWNCLASS and \
box.nonnull() and \
self.known_class.same_constant(cpu.ts.cls_of_box(box)):
@@ -324,8 +339,12 @@
LEVEL_CONSTANT: 'Constant(%r)' % self.constbox,
}[self.level]
+ lb = ''
+ if self.lenbound:
+ lb = ', ' + self.lenbound[2].__repr__()
+
debug_print(indent + mark + 'NotVirtualInfo(%d' % self.position +
- ', ' + l + ', ' + self.intbound.__repr__() + ')')
+ ', ' + l + ', ' + self.intbound.__repr__() + lb + ')')
class VirtualState(object):
def __init__(self, state):
diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -2782,7 +2782,7 @@
res = self.meta_interp(f, [16])
assert res == f(16)
- def test_loopinvariant_array_shrinking(self):
+ def test_loopinvariant_array_shrinking1(self):
myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'i', 'a'])
def f(n):
sa = i = 0
@@ -2798,7 +2798,6 @@
assert res == f(32)
self.check_loops(arraylen_gc=1)
-
class TestOOtype(BasicTests, OOJitMixin):
def test_oohash(self):
@@ -2976,5 +2975,97 @@
self.meta_interp(f, [], enable_opts='')
self.check_loops(new_with_vtable=1)
+ def test_two_loopinvariant_arrays1(self):
+ from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+ myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'i', 'a'])
+ TP = lltype.GcArray(lltype.Signed)
+ def f(n):
+ sa = i = 0
+ a = lltype.malloc(TP, 5)
+ a[4] = 7
+ while i < n:
+ myjitdriver.jit_merge_point(sa=sa, n=n, a=a, i=i)
+ if i < n/2:
+ sa += a[4]
+ if i == n/2:
+ a = lltype.malloc(TP, 3)
+ i += 1
+ return sa
+ res = self.meta_interp(f, [32])
+ assert res == f(32)
+ self.check_tree_loop_count(3)
+
+ def test_two_loopinvariant_arrays2(self):
+ from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+ myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'i', 'a'])
+ TP = lltype.GcArray(lltype.Signed)
+ def f(n):
+ sa = i = 0
+ a = lltype.malloc(TP, 5)
+ a[4] = 7
+ while i < n:
+ myjitdriver.jit_merge_point(sa=sa, n=n, a=a, i=i)
+ if i < n/2:
+ sa += a[4]
+ elif i > n/2:
+ sa += a[2]
+ if i == n/2:
+ a = lltype.malloc(TP, 3)
+ a[2] = 42
+ i += 1
+ return sa
+ res = self.meta_interp(f, [32])
+ assert res == f(32)
+ self.check_tree_loop_count(3)
+
+ def test_two_loopinvariant_arrays3(self):
+ from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+ myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'i', 'a'])
+ TP = lltype.GcArray(lltype.Signed)
+ def f(n):
+ sa = i = 0
+ a = lltype.malloc(TP, 5)
+ a[2] = 7
+ while i < n:
+ myjitdriver.jit_merge_point(sa=sa, n=n, a=a, i=i)
+ if i < n/2:
+ sa += a[2]
+ elif i > n/2:
+ sa += a[3]
+ if i == n/2:
+ a = lltype.malloc(TP, 7)
+ a[3] = 10
+ a[2] = 42
+ i += 1
+ return sa
+ res = self.meta_interp(f, [32])
+ assert res == f(32)
+ self.check_tree_loop_count(2)
+
+ def test_two_loopinvariant_arrays_boxed(self):
+ class A(object):
+ def __init__(self, a):
+ self.a = a
+ from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+ myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'i', 'a'])
+ TP = lltype.GcArray(lltype.Signed)
+ a1 = A(lltype.malloc(TP, 5))
+ a2 = A(lltype.malloc(TP, 3))
+ def f(n):
+ sa = i = 0
+ a = a1
+ a.a[4] = 7
+ while i < n:
+ myjitdriver.jit_merge_point(sa=sa, n=n, a=a, i=i)
+ if i < n/2:
+ sa += a.a[4]
+ if i == n/2:
+ a = a2
+ i += 1
+ return sa
+ res = self.meta_interp(f, [32])
+ assert res == f(32)
+ self.check_loops(arraylen_gc=1, everywhere=True)
+
class TestLLtype(BaseLLtypeTests, LLJitMixin):
pass
More information about the pypy-commit
mailing list