[pypy-commit] pypy resume-refactor: (fijal, rguillebert) Start implementing bytecode representation for
fijal
noreply at buildbot.pypy.org
Fri Jan 17 11:50:41 CET 2014
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: resume-refactor
Changeset: r68709:77a2bb9785d6
Date: 2014-01-17 11:39 +0100
http://bitbucket.org/pypy/pypy/changeset/77a2bb9785d6/
Log: (fijal, rguillebert) Start implementing bytecode representation for
the backend resume code
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
@@ -1502,6 +1502,10 @@
self.setup_list_of_addr2name(asm.list_of_addr2name)
#
self.jitdrivers_sd = codewriter.callcontrol.jitdrivers_sd
+ self.alljitcodes = []
+ for jitcode in codewriter.callcontrol.jitcodes.itervalues():
+ jitcode.global_index = len(self.alljitcodes)
+ self.alljitcodes.append(jitcode)
self.virtualref_info = codewriter.callcontrol.virtualref_info
self.callinfocollection = codewriter.callcontrol.callinfocollection
self.has_libffi_call = codewriter.callcontrol.has_libffi_call
diff --git a/rpython/jit/resume/backend.py b/rpython/jit/resume/backend.py
--- a/rpython/jit/resume/backend.py
+++ b/rpython/jit/resume/backend.py
@@ -1,9 +1,35 @@
from rpython.jit.metainterp.resoperation import rop, ResOperation
from rpython.jit.metainterp.history import ConstInt, Box, Const
-from rpython.jit.resume.frontend import ResumeBytecode, AbstractResumeReader
+from rpython.jit.resume.rescode import ResumeBytecodeBuilder, TAGBOX,\
+ ResumeBytecode
-class LivenessAnalyzer(AbstractResumeReader):
+ # if op.getopnum() == rop.ENTER_FRAME:
+ # descr = op.getdescr()
+ # assert isinstance(descr, JitCode)
+ # self.enter_frame(op.getarg(0).getint(), descr)
+ # elif op.getopnum() == rop.LEAVE_FRAME:
+ # self.leave_frame()
+ # elif op.getopnum() == rop.RESUME_PUT:
+ # self.resume_put(op.getarg(0), op.getarg(1).getint(),
+ # op.getarg(2).getint())
+ # elif op.getopnum() == rop.RESUME_NEW:
+ # self.resume_new(op.result, op.getdescr())
+ # elif op.getopnum() == rop.RESUME_SETFIELD_GC:
+ # self.resume_setfield_gc(op.getarg(0), op.getarg(1),
+ # op.getdescr())
+ # elif op.getopnum() == rop.RESUME_SET_PC:
+ # self.resume_set_pc(op.getarg(0).getint())
+ # elif op.getopnum() == rop.RESUME_CLEAR:
+ # self.resume_clear(op.getarg(0).getint(),
+ # op.getarg(1).getint())
+ # elif not op.is_resume():
+ # pos += 1
+ # continue
+ # else:
+ # xxx
+
+class LivenessAnalyzer(object):
def __init__(self, inputframes=None):
self.liveness = {}
self.frame_starts = [0]
@@ -35,6 +61,9 @@
def resume_set_pc(self, pc):
pass
+ def interpret_until(self, *args):
+ pass
+
def _track(self, allboxes, box):
if box in self.deps:
for dep in self.deps[box].values():
@@ -60,12 +89,12 @@
class ResumeBuilder(object):
def __init__(self, regalloc, frontend_liveness, descr, inputframes=None,
inputlocs=None):
- self.newops = []
self.regalloc = regalloc
self.current_attachment = {}
self.frontend_liveness = frontend_liveness
self.frontend_pos = {}
self.virtuals = {}
+ self.builder = ResumeBytecodeBuilder()
if inputlocs is not None:
i = 0
all = {}
@@ -83,6 +112,30 @@
self.current_attachment[box] = loc_pos
def process(self, op):
+ if op.getopnum() == rop.ENTER_FRAME:
+ self.builder.enter_frame(op.getarg(0).getint(), op.getdescr())
+ elif op.getopnum() == rop.RESUME_PUT:
+ frame_pos = op.getarg(1).getint()
+ pos_in_frame = op.getarg(2).getint()
+ box = op.getarg(0)
+ if isinstance(box, Const):
+ pos = self.builder.encode_const(box)
+ self.builder.resume_put(pos, frame_pos, pos_in_frame)
+ return
+ try:
+ loc = self.regalloc.loc(box, must_exist=True).get_jitframe_position()
+ pos = self.builder.encode(TAGBOX, loc)
+ self.builder.resume_put(pos, frame_pos, pos_in_frame)
+ except KeyError:
+ xxx
+ self.current_attachment[box] = pos
+ self.frontend_pos[box] = (frame_pos, pos_in_frame)
+ elif op.getopnum() == rop.LEAVE_FRAME:
+ self.builder.leave_frame()
+ else:
+ xxx
+ return
+ xxxx
if op.getopnum() == rop.RESUME_PUT:
box = op.getarg(0)
args = op.getarglist()
@@ -119,8 +172,10 @@
return
if v not in self.current_attachment:
return
+ pos = self.builder.encode(TAGBOX, pos)
if self.current_attachment[v] != pos:
frame_index, frame_pos = self.frontend_pos[v]
+ xxx
self.newops.append(ResOperation(rop.RESUME_PUT, [
ConstInt(pos), frame_index, frame_pos],
None))
@@ -137,10 +192,11 @@
for v, loc in self.regalloc.xrm.reg_bindings.iteritems():
if v not in visited:
self._mark_visited(v, loc)
- return len(self.newops)
+ return self.builder.getpos()
def finish(self, parent, parent_position, clt):
- return ResumeBytecode(self.newops, parent, parent_position, clt)
+ return ResumeBytecode(self.builder.build(), parent, parent_position,
+ clt)
def flatten(inputframes):
diff --git a/rpython/jit/resume/frontend.py b/rpython/jit/resume/frontend.py
--- a/rpython/jit/resume/frontend.py
+++ b/rpython/jit/resume/frontend.py
@@ -7,31 +7,6 @@
from rpython.jit.codewriter.jitcode import JitCode
from rpython.rlib import rstack
-class ResumeBytecode(object):
- def __init__(self, opcodes, parent=None, parent_position=-1, loop=None):
- self.opcodes = opcodes
- self.parent = parent
- self.parent_position = parent_position
- self.loop = loop
-
-class ResumeFrame(object):
- def __init__(self, jitcode):
- self.registers = [-1] * jitcode.num_regs()
- self.jitcode = jitcode
- self.pc = -1
-
-TAGCONST = 0x0
-TAGVIRTUAL = 0x2
-TAGBOX = 0x3
-TAGSMALLINT = 0x1
-
-TAGOFFSET = 2
-
-class Virtual(object):
- def __init__(self, pos, descr):
- self.pos = pos
- self.fields = {}
- self.descr = descr
class AbstractResumeReader(object):
@@ -144,6 +119,10 @@
def read_int(self, jitframe_pos):
return self.metainterp.cpu.get_int_value(self.deadframe, jitframe_pos)
+class Dumper(AbstractResumeReader):
+ def __init__(self):
+ xxx
+
class DirectResumeReader(AbstractResumeReader):
""" Directly read values from the jitframe and put them in the blackhole
interpreter
diff --git a/rpython/jit/resume/reader.py b/rpython/jit/resume/reader.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/resume/reader.py
@@ -0,0 +1,145 @@
+
+import sys
+from rpython.jit.metainterp.history import ConstInt
+from rpython.jit.resume import rescode
+
+class ResumeFrame(object):
+ def __init__(self, jitcode):
+ self.registers = [-1] * jitcode.num_regs()
+ self.jitcode = jitcode
+ self.pc = -1
+
+
+class Virtual(object):
+ def __init__(self, pos, descr):
+ self.pos = pos
+ self.fields = {}
+ self.descr = descr
+
+
+class AbstractResumeReader(object):
+ """ A resume reader that can follow resume until given point. Consult
+ the concrete classes for details
+ """
+
+ def __init__(self, staticdata):
+ self.framestack = []
+ self.staticdata = staticdata
+ self.consts = [] # XXX cache?
+ self.virtuals = {}
+ self.virtual_list = []
+
+ def rebuild(self, faildescr):
+ self._rebuild_until(faildescr.rd_resume_bytecode,
+ faildescr.rd_bytecode_position)
+ return self.finish()
+
+ def finish(self):
+ pass
+
+ def enter_frame(self, pc, jitcode):
+ if self.framestack:
+ assert pc != -1
+ self.framestack[-1].pc = pc
+ self.framestack.append(ResumeFrame(jitcode))
+
+ def encode_box(self, pos):
+ return rescode.TAGBOX | (pos << rescode.TAGOFFSET)
+
+ def encode_virtual(self, box):
+ return rescode.TAGVIRTUAL | (self.virtuals[box].pos << rescode.TAGOFFSET)
+
+ def encode_const(self, const):
+ XXX
+ if isinstance(const, ConstInt) and const.getint() < (sys.maxint >> 3):
+ return rescode.TAGSMALLINT | (const.getint() << rescode.TAGOFFSET)
+ self.consts.append(const)
+ return rescode.TAGCONST | ((len(self.consts) - 1) << TAGOFFSET)
+
+ def decode(self, pos):
+ return pos & 0x3, pos >> rescode.TAGOFFSET
+
+ def resume_put(self, jitframe_pos_box, frame_no, frontend_position):
+ XXX
+ if isinstance(jitframe_pos_box, Box):
+ jitframe_pos = self.encode_virtual(jitframe_pos_box)
+ else:
+ jitframe_pos = self.encode_box(jitframe_pos_box.getint())
+ self.framestack[frame_no].registers[frontend_position] = jitframe_pos
+
+ def encode(self, box):
+ xxx
+
+ def resume_new(self, box, descr):
+ # XXX make it a list
+ v = Virtual(len(self.virtual_list), descr)
+ self.virtuals[box] = v
+ self.virtual_list.append(v)
+
+ def resume_setfield_gc(self, box, fieldbox, descr):
+ # XXX optimize fields
+ self.virtuals[box].fields[descr] = self.encode(fieldbox)
+
+ def resume_clear(self, frame_no, frontend_position):
+ self.framestack[frame_no].registers[frontend_position] = -1
+
+ def resume_put_const(self, const, frame_no, frontend_position):
+ pos = self.encode_const(const)
+ self.framestack[frame_no].registers[frontend_position] = pos
+
+ def resume_set_pc(self, pc):
+ self.framestack[-1].pc = pc
+
+ def leave_frame(self):
+ self.framestack.pop()
+
+ def _rebuild_until(self, rb, position):
+ if rb.parent is not None:
+ self._rebuild_until(rb.parent, rb.parent_position)
+ self.interpret_until(rb.opcodes, position)
+
+ def read(self, pos):
+ return ord(self.bytecode.opcodes[pos])
+
+ def read_short(self, pos):
+ return self.read(pos) + (self.read(pos + 1) << 16)
+
+ def interpret_until(self, bytecode, until, pos=0):
+ self.bytecode = bytecode
+ while pos < until:
+ op = ord(bytecode.opcodes[pos])
+ if op == rescode.UNUSED:
+ raise Exception("malformed bytecode")
+ elif op == rescode.ENTER_FRAME:
+ pc = self.read_short(pos + 1) - 1
+ jitcode = self.staticdata.alljitcodes[self.read_short(pos + 3)]
+ self.enter_frame(pc, jitcode)
+ pos += 5
+ elif op == rescode.RESUME_PUT:
+ encoded = self.read_short(pos + 1)
+ frame_pos = self.read(pos + 3)
+ pos_in_frame = self.read(pos + 4)
+ self.resume_put(encoded, frame_pos, pos_in_frame)
+ pos += 5
+ else:
+ xxx
+ self.bytecode = None
+
+ def read_int(self, jitframe_pos):
+ return self.metainterp.cpu.get_int_value(self.deadframe, jitframe_pos)
+
+class Dumper(AbstractResumeReader):
+ def __init__(self, staticdata):
+ AbstractResumeReader.__init__(self, staticdata)
+ self.l = []
+
+ def enter_frame(self, pc, jitcode):
+ self.l.append("enter_frame %d %s" % (pc, jitcode.name))
+
+ def resume_put(self, encoded, frame_pos, pos_in_frame):
+ tag, index = self.decode(encoded)
+ self.l.append("resume_put (%d, %d) %d %d" % (tag, index, frame_pos,
+ pos_in_frame))
+
+ def finish(self):
+ return "\n".join(self.l)
diff --git a/rpython/jit/resume/rescode.py b/rpython/jit/resume/rescode.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/resume/rescode.py
@@ -0,0 +1,66 @@
+
+from rpython.jit.metainterp.history import ConstInt
+
+UNUSED, ENTER_FRAME, LEAVE_FRAME, RESUME_PUT = range(4)
+
+TAGCONST = 0x0
+TAGVIRTUAL = 0x2
+TAGBOX = 0x3
+TAGSMALLINT = 0x1
+
+TAGOFFSET = 2
+
+class ResumeBytecode(object):
+ def __init__(self, opcodes, parent=None, parent_position=-1, loop=None):
+ self.opcodes = opcodes
+ self.parent = parent
+ self.parent_position = parent_position
+ self.loop = loop
+
+ def dump(self, staticdata, resume_pos):
+ from rpython.jit.resume.reader import Dumper
+
+ d = Dumper(staticdata)
+ d.interpret_until(self, resume_pos)
+ return d.finish()
+
+class ResumeBytecodeBuilder(object):
+ def __init__(self):
+ self.l = []
+
+ def getpos(self):
+ return len(self.l)
+
+ def build(self):
+ return "".join(self.l)
+
+ def write(self, i):
+ assert 0 <= i < 256
+ self.l.append(chr(i))
+
+ def write_short(self, i):
+ assert 0 <= i < 0x1000
+ self.write(i & 0xff)
+ self.write(i >> 8)
+
+ def enter_frame(self, pc, jitcode):
+ self.write(ENTER_FRAME)
+ self.write_short(pc + 1) # can be -1 !
+ self.write_short(jitcode.global_index)
+
+ def leave_frame(self):
+ self.write(LEAVE_FRAME)
+
+ def encode(self, tag, loc):
+ return tag | (loc << 2)
+
+ def encode_const(self, const):
+ if isinstance(const, ConstInt) and 0 <= const.getint() < 0x4000:
+ return TAGSMALLINT | (const.getint() << 2)
+ xxx
+
+ def resume_put(self, pos, frame_pos, pos_in_frame):
+ self.write(RESUME_PUT)
+ self.write_short(pos)
+ self.write(frame_pos)
+ self.write(pos_in_frame)
diff --git a/rpython/jit/resume/test/test_backend.py b/rpython/jit/resume/test/test_backend.py
--- a/rpython/jit/resume/test/test_backend.py
+++ b/rpython/jit/resume/test/test_backend.py
@@ -10,7 +10,8 @@
class MockJitCode(JitCode):
def __init__(self, no):
self.no = no
- self.name = 'frame %d' % no
+ self.global_index = no
+ self.name = 'frame-%d' % no
def num_regs(self):
return self.no
@@ -18,13 +19,20 @@
def __repr__(self):
return 'MockJitCode(%d)' % self.no
+class MockStaticData(object):
+ def __init__(self, *jitcodes):
+ self.alljitcodes = list(jitcodes)
+
+def preparse(inp):
+ return "\n".join([s.strip() for s in inp.split("\n") if s.strip()])
+
class ResumeTest(object):
def setup_method(self, meth):
self.cpu = self.CPUClass(None, None)
self.cpu.setup_once()
def test_simple(self):
- jitcode = MockJitCode(3)
+ jitcode = MockJitCode(1)
loop = parse("""
[i0]
enter_frame(-1, descr=jitcode)
@@ -37,16 +45,16 @@
self.cpu.compile_loop(None, loop.inputargs, loop.operations,
looptoken)
descr = loop.operations[3].getdescr()
- assert descr.rd_bytecode_position == 3
- expected_resume = parse("""
- []
- enter_frame(-1, descr=jitcode)
- resume_put(28, 0, 2)
- resume_put_const(1, 0, 1)
- leave_frame()
- """, namespace={'jitcode': jitcode})
- equaloplists(descr.rd_resume_bytecode.opcodes,
- expected_resume.operations)
+ assert descr.rd_bytecode_position == 15
+ staticdata = MockStaticData(None, jitcode)
+ res = descr.rd_resume_bytecode.dump(staticdata,
+ descr.rd_bytecode_position)
+ expected_resume = preparse("""
+ enter_frame -1 frame-1
+ resume_put (3, 28) 0 2
+ resume_put (1, 1) 0 1
+ """)
+ assert res == expected_resume
def test_resume_new(self):
jitcode = JitCode("name")
diff --git a/rpython/jit/resume/test/test_frontend.py b/rpython/jit/resume/test/test_frontend.py
--- a/rpython/jit/resume/test/test_frontend.py
+++ b/rpython/jit/resume/test/test_frontend.py
@@ -2,8 +2,9 @@
from rpython.jit.tool.oparser import parse
from rpython.jit.codewriter.jitcode import JitCode
from rpython.jit.metainterp.history import AbstractDescr, Const, INT, Stats
-from rpython.jit.resume.frontend import rebuild_from_resumedata,\
- ResumeBytecode, AbstractResumeReader
+from rpython.jit.resume.frontend import rebuild_from_resumedata
+from rpython.jit.resume.rescode import ResumeBytecode
+from rpython.jit.resume.reader import AbstractResumeReader
from rpython.jit.metainterp.resoperation import rop
from rpython.jit.codewriter.format import unformat_assembler
from rpython.jit.codewriter.codewriter import CodeWriter
More information about the pypy-commit
mailing list