Author: Maciej Fijalkowski <[email protected]>
Branch: optmodel-refactor
Changeset: r66282:597c1b69f100
Date: 2013-08-21 17:39 +0200
http://bitbucket.org/pypy/pypy/changeset/597c1b69f100/
Log: Progress on building new sort of bytecode - intermediate checkin (I
just need a point of reference)
diff --git a/rpython/jit/codewriter/assembler.py
b/rpython/jit/codewriter/assembler.py
--- a/rpython/jit/codewriter/assembler.py
+++ b/rpython/jit/codewriter/assembler.py
@@ -36,7 +36,7 @@
self.fix_labels()
self.check_result()
if jitcode is None:
- jitcode = JitCode(ssarepr.name)
+ jitcode = JitCode(ssarepr.name, self._count_jitcodes)
jitcode._ssarepr = ssarepr
self.make_jitcode(jitcode)
if self._count_jitcodes < 20: # stop if we have a lot of them
diff --git a/rpython/jit/codewriter/call.py b/rpython/jit/codewriter/call.py
--- a/rpython/jit/codewriter/call.py
+++ b/rpython/jit/codewriter/call.py
@@ -22,6 +22,7 @@
self.cpu = cpu
self.jitdrivers_sd = jitdrivers_sd
self.jitcodes = {} # map {graph: jitcode}
+ self.alljitcodes = [] # list of all jitcodes
self.unfinished_graphs = [] # list of graphs with pending jitcodes
self.callinfocollection = CallInfoCollection()
if hasattr(cpu, 'rtyper'): # for tests
@@ -167,8 +168,9 @@
'%s has _gctransformer_hint_close_stack_' % (graph,))
#
fnaddr, calldescr = self.get_jitcode_calldescr(graph)
- jitcode = JitCode(graph.name, fnaddr, calldescr,
+ jitcode = JitCode(graph.name, len(self.jitcodes), fnaddr,
calldescr,
called_from=called_from)
+ self.alljitcodes.append(jitcode)
self.jitcodes[graph] = jitcode
self.unfinished_graphs.append(graph)
return jitcode
diff --git a/rpython/jit/codewriter/jitcode.py
b/rpython/jit/codewriter/jitcode.py
--- a/rpython/jit/codewriter/jitcode.py
+++ b/rpython/jit/codewriter/jitcode.py
@@ -8,8 +8,10 @@
_empty_r = []
_empty_f = []
- def __init__(self, name, fnaddr=None, calldescr=None, called_from=None):
+ def __init__(self, name, number=-1, fnaddr=None, calldescr=None,
+ called_from=None):
self.name = name
+ self.number = number
self.fnaddr = fnaddr
self.calldescr = calldescr
self.is_portal = False
diff --git a/rpython/jit/metainterp/blackhole.py
b/rpython/jit/metainterp/blackhole.py
--- a/rpython/jit/metainterp/blackhole.py
+++ b/rpython/jit/metainterp/blackhole.py
@@ -1608,10 +1608,10 @@
def resume_in_blackhole(metainterp_sd, jitdriver_sd, resumedescr, deadframe,
all_virtuals=None):
- from rpython.jit.metainterp.resume import blackhole_from_resumedata
+ from rpython.jit.metainterp.resume2 import blackhole_from_resumedata
#debug_start('jit-blackhole')
blackholeinterp = blackhole_from_resumedata(
- metainterp_sd.blackholeinterpbuilder,
+ metainterp_sd,
jitdriver_sd,
resumedescr,
deadframe,
diff --git a/rpython/jit/metainterp/compile.py
b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -133,7 +133,8 @@
[ResOperation(rop.LABEL, jumpargs, None,
descr=jitcell_token)]
try:
- optimize_trace(metainterp_sd, part, enable_opts)
+ optimize_trace(metainterp_sd, metainterp.resume_bc.boxes, part,
+ enable_opts)
except InvalidLoop:
return None
target_token = part.operations[0].getdescr()
@@ -160,7 +161,7 @@
jumpargs = part.operations[-1].getarglist()
try:
- optimize_trace(metainterp_sd, part, enable_opts)
+ optimize_trace(metainterp_sd, allboxes, part, enable_opts)
except InvalidLoop:
return None
@@ -212,7 +213,7 @@
orignial_label = label.clone()
assert label.getopnum() == rop.LABEL
try:
- optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts)
+ optimize_trace(metainterp_sd, allboxes, part,
jitdriver_sd.warmstate.enable_opts)
except InvalidLoop:
# Fall back on jumping to preamble
target_token = label.getdescr()
@@ -222,7 +223,8 @@
[ResOperation(rop.JUMP, inputargs[:],
None, descr=loop_jitcell_token)]
try:
- optimize_trace(metainterp_sd, part,
jitdriver_sd.warmstate.enable_opts,
+ optimize_trace(metainterp_sd, allboxes, part,
+ jitdriver_sd.warmstate.enable_opts,
inline_short_preamble=False)
except InvalidLoop:
return None
@@ -630,6 +632,7 @@
def copy_all_attributes_into(self, res):
# XXX a bit ugly to have to list them all here
+ # XXX kill that
res.rd_snapshot = self.rd_snapshot
res.rd_frame_info_list = self.rd_frame_info_list
res.rd_numb = self.rd_numb
@@ -637,6 +640,8 @@
res.rd_virtuals = self.rd_virtuals
res.rd_pendingfields = self.rd_pendingfields
res.rd_count = self.rd_count
+ res.rd_bytecode = self.rd_bytecode
+ res.rd_bytecode_position = self.rd_bytecode_position
def _clone_if_mutable(self):
res = ResumeGuardDescr()
@@ -851,7 +856,8 @@
else:
inline_short_preamble = True
try:
- optimize_trace(metainterp_sd, new_trace, state.enable_opts,
inline_short_preamble)
+ optimize_trace(metainterp_sd, allboxes,
+ new_trace, state.enable_opts, inline_short_preamble)
except InvalidLoop:
debug_print("compile_new_bridge: got an InvalidLoop")
# XXX I am fairly convinced that optimize_bridge cannot actually raise
diff --git a/rpython/jit/metainterp/optimizeopt/__init__.py
b/rpython/jit/metainterp/optimizeopt/__init__.py
--- a/rpython/jit/metainterp/optimizeopt/__init__.py
+++ b/rpython/jit/metainterp/optimizeopt/__init__.py
@@ -48,7 +48,8 @@
return optimizations, unroll
-def optimize_trace(metainterp_sd, loop, enable_opts,
inline_short_preamble=True):
+def optimize_trace(metainterp_sd, allboxes, loop, enable_opts,
+ inline_short_preamble=True):
"""Optimize loop.operations to remove internal overheadish operations.
"""
@@ -60,11 +61,11 @@
if unroll:
optimize_unroll(metainterp_sd, loop, optimizations,
inline_short_preamble)
else:
- optimizer = Optimizer(metainterp_sd, loop, optimizations)
+ optimizer = Optimizer(metainterp_sd, loop, allboxes, optimizations)
optimizer.propagate_all_forward()
finally:
debug_stop("jit-optimize")
-
+
if __name__ == '__main__':
print ALL_OPTS_NAMES
diff --git a/rpython/jit/metainterp/optimizeopt/heap.py
b/rpython/jit/metainterp/optimizeopt/heap.py
--- a/rpython/jit/metainterp/optimizeopt/heap.py
+++ b/rpython/jit/metainterp/optimizeopt/heap.py
@@ -1,5 +1,6 @@
import os
+from rpython.rlib.objectmodel import specialize
from rpython.jit.metainterp.history import Const
from rpython.jit.metainterp.jitexc import JitException
from rpython.jit.metainterp.optimizeopt.optimizer import Optimization,
MODE_ARRAY, LEVEL_KNOWNCLASS
diff --git a/rpython/jit/metainterp/optimizeopt/optimizer.py
b/rpython/jit/metainterp/optimizeopt/optimizer.py
--- a/rpython/jit/metainterp/optimizeopt/optimizer.py
+++ b/rpython/jit/metainterp/optimizeopt/optimizer.py
@@ -1,12 +1,13 @@
from rpython.jit.metainterp import jitprof, resume, compile
from rpython.jit.metainterp.executor import execute_nonspec
-from rpython.jit.metainterp.history import BoxInt, BoxFloat, Const, ConstInt,
REF
+from rpython.jit.metainterp.history import BoxInt, BoxFloat, Const, ConstInt,
REF, AbstractFailDescr
from rpython.jit.metainterp.optimizeopt.intutils import IntBound,
IntUnbounded, \
ImmutableIntUnbounded, \
IntLowerBound, MININT,
MAXINT
from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
from rpython.jit.metainterp.resoperation import rop, ResOperation,
AbstractResOp
from rpython.jit.metainterp.typesystem import llhelper
+from rpython.jit.metainterp.resume2 import OptimizerResumeInterpreter
from rpython.tool.pairtype import extendabletype
from rpython.rlib.debug import debug_print
from rpython.rlib.objectmodel import specialize
@@ -340,7 +341,21 @@
class Optimizer(Optimization):
- def __init__(self, metainterp_sd, loop, optimizations=None):
+ def __init__(self, metainterp_sd, loop, allboxes, optimizations=None):
+ self.allboxes = {}
+ for k, v in allboxes.iteritems():
+ self.allboxes[v] = k
+ # we fish bytecode from the loop
+ for op in loop.operations:
+ if op.is_guard():
+ descr = op.getdescr()
+ assert isinstance(descr, AbstractFailDescr)
+ bc = descr.rd_bytecode
+ jitcodes = metainterp_sd.alljitcodes
+ self.resume_bc = OptimizerResumeInterpreter(bc, jitcodes)
+ break
+ else:
+ self.resume_bc = None # trivial case
self.metainterp_sd = metainterp_sd
self.cpu = metainterp_sd.cpu
self.loop = loop
@@ -570,6 +585,9 @@
del self.replaces_guard[op]
return
else:
+ descr = op.getdescr()
+ assert isinstance(descr, AbstractFailDescr)
+ self.resume_bc.interpret_until(descr.rd_bytecode_position)
op = self.store_final_boxes_in_guard(op, pendingfields)
elif op.can_raise():
self.exception_might_have_happened = True
@@ -594,9 +612,10 @@
assert pendingfields is not None
descr = op.getdescr()
assert isinstance(descr, compile.ResumeGuardDescr)
- modifier = resume.ResumeDataVirtualAdder(descr, self.resumedata_memo)
+ #modifier = resume.ResumeDataVirtualAdder(descr, self.resumedata_memo)
try:
- newboxes = modifier.finish(self, pendingfields)
+ #newboxes = modifier.finish(self, pendingfields)
+ newboxes = self.resume_bc.get_current_boxes(self.allboxes)
if len(newboxes) > self.metainterp_sd.options.failargs_limit:
raise resume.TagOverflow
except resume.TagOverflow:
diff --git a/rpython/jit/metainterp/pyjitpl.py
b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -6,6 +6,7 @@
from rpython.jit.codewriter.effectinfo import EffectInfo
from rpython.jit.codewriter.jitcode import JitCode, SwitchDictDescr
from rpython.jit.metainterp import history, compile, resume, executor, jitexc
+from rpython.jit.metainterp import resume2
from rpython.jit.metainterp.heapcache import HeapCache
from rpython.jit.metainterp.history import (Const, ConstInt, ConstPtr,
ConstFloat, Box, TargetToken)
@@ -1467,9 +1468,10 @@
logger_noopt = None
logger_ops = None
- def __init__(self, cpu, options,
+ def __init__(self, cpu, options, alljitcodes,
ProfilerClass=EmptyProfiler, warmrunnerdesc=None):
self.cpu = cpu
+ self.alljitcodes = alljitcodes
self.stats = self.cpu.stats
self.options = options
self.logger_noopt = Logger(self)
@@ -1675,6 +1677,13 @@
return self.jitdriver_sd is not None and jitcode is
self.jitdriver_sd.mainjitcode
def newframe(self, jitcode, greenkey=None):
+ if not self.framestack:
+ pc = 0
+ boxlist = []
+ else:
+ pc = self.framestack[-1].pc
+ boxlist = self.framestack[-1].get_list_of_active_boxes(True)
+ self.resume_bc.enter_function(jitcode, pc, boxlist)
if jitcode.is_portal:
self.portal_call_depth += 1
self.call_ids.append(self.current_call_id)
@@ -1691,6 +1700,7 @@
return f
def popframe(self):
+ self.resume_bc.leave_function()
frame = self.framestack.pop()
jitcode = frame.jitcode
if jitcode.is_portal:
@@ -1808,8 +1818,14 @@
saved_pc = frame.pc
if resumepc >= 0:
frame.pc = resumepc
- resume.capture_resumedata(self.framestack, virtualizable_boxes,
- self.virtualref_boxes, resumedescr)
+ else:
+ resumepc = frame.pc
+ boxlist = self.framestack[-1].get_list_of_active_boxes(False)
+ else:
+ boxlist = []
+ #resume.capture_resumedata(self.framestack, virtualizable_boxes,
+ # self.virtualref_boxes, resumedescr)
+ self.resume_bc.capture_resumedata(resumedescr, resumepc, boxlist)
if self.framestack:
self.framestack[-1].pc = saved_pc
@@ -2223,6 +2239,7 @@
resume_at_jump_descr, try_disabling_unroll=False):
num_green_args = self.jitdriver_sd.num_green_args
greenkey = original_boxes[:num_green_args]
+ self.resume_bc.finish(self, start)
if not self.partial_trace:
ptoken = self.get_procedure_token(greenkey)
if ptoken is not None and ptoken.target_tokens is not None:
@@ -2356,6 +2373,7 @@
# ----- make a new frame -----
self.portal_call_depth = -1 # always one portal around
self.framestack = []
+ self.resume_bc = resume2.ResumeBytecodeBuilder(self.staticdata)
f = self.newframe(self.jitdriver_sd.mainjitcode)
f.setup_call(original_boxes)
assert self.portal_call_depth == 0
@@ -2371,6 +2389,9 @@
try:
self.portal_call_depth = -1 # always one portal around
self.history = history.History()
+ self.resume_bc = resume2.ResumeBytecodeBuilder(self.staticdata)
+ self.resume_bc.start_from_descr(resumedescr)
+ xxx
inputargs_and_holes = self.rebuild_state_after_failure(resumedescr,
deadframe)
self.history.inputargs = [box for box in inputargs_and_holes if
box]
diff --git a/rpython/jit/metainterp/resume2.py
b/rpython/jit/metainterp/resume2.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/metainterp/resume2.py
@@ -0,0 +1,237 @@
+
+""" The new resume that records bytecode. The idea is that bytecode is
+incremental and minimal for the case the guard is never incoked. However,
+if the guard fails it can be compressed into a starting point.
+
+opcodes:
+
+UPDATE_PC <pc> [list-of-alive-boxes]
+ENTER_FRAME <func no> <pc> [list-of-alive-boxes]
+LEAVE_FRAME
+
+"""
+
+from rpython.rlib import rstack
+
+ENTER_FRAME = chr(0)
+LEAVE_FRAME = chr(1)
+CAPTURE_POINT = chr(2)
+
+BC_NAMES = ['ENTER_FRAME', 'LEAVE_FRAME', 'CAPTURE_POINT']
+
+class ResumeBytecodeBuilder(object):
+ def __init__(self, metainterp_sd):
+ self.bc = []
+ self.boxes = {}
+ self.metainterp_sd = metainterp_sd
+
+ def enumerate_box(self, box):
+ if box in self.boxes:
+ return self.boxes[box]
+ else:
+ no = len(self.boxes)
+ self.boxes[box] = no
+ return no
+
+ def write(self, c):
+ self.bc.append(c)
+
+ def write_short(self, s):
+ assert 0 <= s <= (2**16 - 1)
+ self.write(chr(s >> 8))
+ self.write(chr(s & 0xff))
+
+ def write_list(self, l):
+ self.write_short(len(l))
+ for item in l:
+ self.write_short(item)
+
+ def enter_function(self, jitcode, pc, boxlist):
+ self.write(ENTER_FRAME)
+ self.write_short(jitcode.number)
+ self.write_short(pc)
+ self.write_list([self.enumerate_box(box) for box in boxlist])
+
+ def leave_function(self):
+ self.write(LEAVE_FRAME)
+
+ def start_from_descr(self, descr):
+ xxx
+
+ def capture_resumedata(self, descr, resumepc, boxlist):
+ self.write(CAPTURE_POINT)
+ self.write_short(resumepc)
+ self.write_list([self.enumerate_box(box) for box in boxlist])
+ descr.rd_bytecode_position = len(self.bc)
+
+ def finish(self, metainterp, start):
+ from rpython.jit.metainterp.history import AbstractFailDescr
+
+ assert start == 0
+ finished_bc = ''.join(self.bc)
+ for op in metainterp.history.operations:
+ if op.is_guard():
+ descr = op.getdescr()
+ assert isinstance(descr, AbstractFailDescr)
+ descr.rd_bytecode = finished_bc
+ print_bc(finished_bc, self.metainterp_sd.alljitcodes)
+
+class AbstractBytecodeInterpreter(object):
+ def __init__(self, bc, alljitcodes):
+ self.bc = bc
+ self.alljitcodes = alljitcodes
+ self.init()
+
+ def init(self):
+ pass
+
+ def read_short(self):
+ res = (ord(self.bc[self.pos]) << 8) + ord(self.bc[self.pos + 1])
+ self.pos += 2
+ return res
+
+ def read_list(self):
+ length = self.read_short()
+ l = []
+ for i in range(length):
+ l.append(self.read_short())
+ return l
+
+ def interpret(self):
+ self.pos = 0
+ self.interpret_until(len(self.bc))
+
+ def interpret_until(self, stop):
+ self.stop = stop
+ while self.pos < stop:
+ opcode = self.bc[self.pos]
+ self.pos += 1
+ if opcode == ENTER_FRAME:
+ jitcode = self.alljitcodes[self.read_short()]
+ pc = self.read_short()
+ boxlist = self.read_list()
+ self.ENTER_FRAME(jitcode, pc, boxlist)
+ elif opcode == LEAVE_FRAME:
+ self.LEAVE_FRAME()
+ elif opcode == CAPTURE_POINT:
+ pc = self.read_short()
+ boxlist = self.read_list()
+ self.CAPTURE_POINT(pc, boxlist)
+
+class BytecodePrinter(AbstractBytecodeInterpreter):
+ def ENTER_FRAME(self, jitcode, pc, boxnos):
+ print "ENTER_FRAME %s %d %s" % (jitcode.name, pc, boxnos)
+
+ def CAPTURE_POINT(self, pc, boxlist):
+ print "CAPTURE_POINT %d %s" % (pc, boxlist)
+
+ def LEAVE_FRAME(self):
+ print "LEAVE_FRAME"
+
+class DirectResumeBuilder(AbstractBytecodeInterpreter):
+ def init(self):
+ self.pos = 0
+ self.framestack = []
+
+ def ENTER_FRAME(self, jitcode, pc, boxlist):
+ self.framestack.append((jitcode, pc, boxlist))
+
+ def CAPTURE_POINT(self, pc, boxlist):
+ if self.pos == self.stop:
+ self.framestack.append((None, pc, boxlist))
+
+ def LEAVE_FRAME(self):
+ self.framestack.pop()
+
+class OptimizerResumeInterpreter(AbstractBytecodeInterpreter):
+ def init(self):
+ self.pos = 0
+ self.framestack = []
+ self.cur_len = 0
+ self.cur_boxlist = None
+
+ def get_current_boxes(self, allboxes):
+ newboxes = [None] * (self.cur_len + len(self.cur_boxlist))
+ i = 0
+ j = 0
+ while i < len(self.framestack):
+ boxlist = self.framestack[i]
+ newboxes[j:j + len(boxlist)] = boxlist
+ i += 1
+ j += len(boxlist)
+ newboxes[j:] = self.cur_boxlist
+ return [allboxes[i] for i in newboxes]
+
+ def ENTER_FRAME(self, jitcode, pc, boxlist):
+ self.framestack.append(boxlist)
+ self.cur_len += len(boxlist)
+
+ def CAPTURE_POINT(self, pc, boxlist):
+ self.cur_boxlist = boxlist
+
+ def LEAVE_FRAME(self):
+ el = self.framestack.pop()
+ self.cur_len -= len(el)
+
+def print_bc(bc, jitcodes):
+ BytecodePrinter(bc, jitcodes).interpret()
+
+class InfoFiller(object):
+ def __init__(self, cpu, deadframe, bhinterp, boxlist):
+ self.cpu = cpu
+ self.boxlist = boxlist
+ self.deadframe = deadframe
+ self.bhinterp = bhinterp
+
+ def callback_i(self, index, register_index):
+ backend_index = self.boxlist[index]
+ intval = self.cpu.get_int_value(self.deadframe, backend_index)
+ self.bhinterp.setarg_i(register_index, intval)
+
+ def callback_r(self, index, register_index):
+ xxx
+
+ def callback_f(self, index, register_index):
+ xxx
+
+def blackhole_from_resumedata(metainterp_sd, jitdriver_sd, descr,
+ deadframe, all_virtuals=None):
+ # The initialization is stack-critical code: it must not be interrupted by
+ # StackOverflow, otherwise the jit_virtual_refs are left in a dangling
state.
+ assert all_virtuals is None
+ blackholeinterpbuilder = metainterp_sd.blackholeinterpbuilder
+ alljitcodes = metainterp_sd.alljitcodes
+ rstack._stack_criticalcode_start()
+ try:
+ pos = descr.rd_bytecode_position
+ rb = DirectResumeBuilder(descr.rd_bytecode, alljitcodes)
+ rb.interpret_until(pos)
+ framestack = rb.framestack
+ finally:
+ rstack._stack_criticalcode_stop()
+
+ #
+ # First get a chain of blackhole interpreters whose length is given
+ # by the size of framestack. The first one we get must be
+ # the bottom one, i.e. the last one in the chain, in order to make
+ # the comment in BlackholeInterpreter.setposition() valid.
+ nextbh = None
+ for i in range(len(framestack)):
+ curbh = blackholeinterpbuilder.acquire_interp()
+ curbh.nextblackholeinterp = nextbh
+ nextbh = curbh
+ firstbh = nextbh
+ #
+ # Now fill the blackhole interpreters with resume data.
+ curbh = firstbh
+ for i in range(len(framestack) - 1, 0, -1):
+ jitcode = framestack[i - 1][0]
+ pc = framestack[i - 1][1]
+ boxlist = framestack[i][2]
+ curbh.setposition(jitcode, pc)
+ info = curbh.get_current_position_info()
+ filler = InfoFiller(metainterp_sd.cpu, deadframe, curbh, boxlist)
+ info.enumerate_vars(filler.callback_i, filler.callback_r,
+ filler.callback_f, None)
+ curbh = curbh.nextblackholeinterp
+ return firstbh
diff --git a/rpython/jit/metainterp/test/test_loop.py
b/rpython/jit/metainterp/test/test_loop.py
--- a/rpython/jit/metainterp/test/test_loop.py
+++ b/rpython/jit/metainterp/test/test_loop.py
@@ -908,5 +908,11 @@
res = self.meta_interp(f, [20, 10])
assert res == f(20, 10)
-class TestLLtype(LoopTest, LLJitMixin):
- pass
+#class TestLLtype(LoopTest, LLJitMixin):
+ #pass
+
+class TestLLtype2(LoopTest, LLJitMixin):
+ enable_opts = ''
+
+ def check_resops(self, *args, **kwds):
+ pass
diff --git a/rpython/jit/metainterp/warmspot.py
b/rpython/jit/metainterp/warmspot.py
--- a/rpython/jit/metainterp/warmspot.py
+++ b/rpython/jit/metainterp/warmspot.py
@@ -198,7 +198,8 @@
elif self.opt.listops:
self.prejit_optimizations_minimal_inline(policy, graphs)
- self.build_meta_interp(ProfilerClass)
+ self.build_meta_interp(ProfilerClass,
+ self.codewriter.callcontrol.alljitcodes)
self.make_args_specifications()
#
from rpython.jit.metainterp.virtualref import VirtualRefInfo
@@ -427,9 +428,10 @@
cpu.supports_singlefloats = False
self.cpu = cpu
- def build_meta_interp(self, ProfilerClass):
+ def build_meta_interp(self, ProfilerClass, alljitcodes):
self.metainterp_sd = MetaInterpStaticData(self.cpu,
self.opt,
+ alljitcodes,
ProfilerClass=ProfilerClass,
warmrunnerdesc=self)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit