Author: Maciej Fijalkowski <fij...@gmail.com> Branch: resume-refactor Changeset: r68960:672bb5aed066 Date: 2014-01-27 10:35 +0100 http://bitbucket.org/pypy/pypy/changeset/672bb5aed066/
Log: implement new and new_with_vtable 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 @@ -1,125 +1,13 @@ from rpython.jit.metainterp.resoperation import rop from rpython.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, ConstInt,\ - INT, REF, Const + INT, REF, FLOAT from rpython.jit.metainterp import history from rpython.jit.resume.reader import AbstractResumeReader from rpython.jit.resume.rescode import TAGBOX, TAGCONST, TAGSMALLINT,\ TAGVIRTUAL, CLEAR_POSITION -# class AbstractResumeReader(object): -# """ A resume reader that can follow resume until given point. Consult -# the concrete classes for details -# """ - -# def __init__(self): -# self.framestack = [] -# 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 TAGBOX | (pos << TAGOFFSET) - -# def encode_virtual(self, box): -# return TAGVIRTUAL | (self.virtuals[box].pos << TAGOFFSET) - -# def encode_const(self, const): -# if isinstance(const, ConstInt) and const.getint() < (sys.maxint >> 3): -# return TAGSMALLINT | (const.getint() << TAGOFFSET) -# self.consts.append(const) -# return TAGCONST | ((len(self.consts) - 1) << TAGOFFSET) - -# def decode(self, pos): -# return pos & 0x3, pos >> TAGOFFSET - -# def resume_put(self, jitframe_pos_box, frame_no, frontend_position): -# 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 interpret_until(self, bytecode, until, pos=0): -# while pos < until: -# op = bytecode[pos] -# if op == rescode.ENTER_FRAME: -# xxx -# 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 -# pos += 1 - -# def read_int(self, jitframe_pos): -# return self.metainterp.cpu.get_int_value(self.deadframe, jitframe_pos) - - class DirectResumeReader(AbstractResumeReader): """ Directly read values from the jitframe and put them in the blackhole interpreter @@ -129,6 +17,7 @@ self.bhinterpbuilder = binterpbuilder self.cpu = cpu self.deadframe = deadframe + self.virtuals_cache = {} AbstractResumeReader.__init__(self, metainterp_sd) def finish(self): @@ -154,38 +43,55 @@ def store_int_value(self, curbh, i, encoded_pos): if encoded_pos == CLEAR_POSITION: return + val = self.getint(encoded_pos) + curbh.registers_i[i] = val + + def getint(self, encoded_pos): tag, index = self.decode(encoded_pos) if tag == TAGBOX: - curbh.registers_i[i] = self.cpu.get_int_value(self.deadframe, index) + return self.cpu.get_int_value(self.deadframe, index) elif tag == TAGSMALLINT: - curbh.registers_i[i] = index + return index else: xxx - return - xxx - if jitframe_pos >= 0: - curbh.registers_i[i] = self.cpu.get_int_value( - self.deadframe, jitframe_pos) - elif jitframe_pos < -1: - curbh.registers_i[i] = self.consts[-jitframe_pos - 2].getint() def store_ref_value(self, curbh, i, encoded_pos): if encoded_pos == CLEAR_POSITION: return + curbh.registers_r[i] = self.getref(encoded_pos) + + def getref(self, encoded_pos): tag, index = self.decode(encoded_pos) if tag == TAGBOX: - curbh.registers_r[i] = self.cpu.get_ref_value(self.deadframe, index) + return self.cpu.get_ref_value(self.deadframe, index) elif tag == TAGCONST: - curbh.registers_r[i] = self.consts[index].getref_base() + return self.consts[index].getref_base() + elif tag == TAGVIRTUAL: + return self.allocate_virtual(index) else: xxx - return - xxxx - if jitframe_pos >= 0: - curbh.registers_r[i] = self.cpu.get_ref_value( - self.deadframe, jitframe_pos) - elif jitframe_pos < -1: - curbh.registers_r[i] = self.consts[-jitframe_pos - 2].getref_base() + + def allocate_virtual(self, index): + try: + return self.virtuals_cache[index] + except KeyError: + pass + val = self.virtuals[index].allocate_direct(self.cpu) + self.virtuals_cache[index] = val + fields = self.virtuals[index].fields + for fielddescr, encoded_field_pos in fields.iteritems(): + self.setfield_gc(val, encoded_field_pos, fielddescr) + return val + + def setfield_gc(self, struct, encoded_field_pos, fielddescr): + if fielddescr.kind == INT: + intval = self.getint(encoded_field_pos) + self.cpu.bh_setfield_gc_i(struct, intval, fielddescr) + elif fielddescr.kind == REF: + refval = self.getref(encoded_field_pos) + self.cpu.bh_setfield_gc_r(struct, refval, fielddescr) + elif fielddescr.kind == FLOAT: + xxx def store_float_value(self, curbh, i, jitframe_pos): xxx @@ -236,10 +142,10 @@ else: assert tag == TAGVIRTUAL virtual = self.virtuals[pos] - virtual_box = self.allocate_struct(virtual) + virtual_box = virtual.allocate_box(self.metainterp) + self.cache[encoded_pos] = virtual_box for fielddescr, encoded_field_pos in virtual.fields.iteritems(): self.setfield_gc(virtual_box, encoded_field_pos, fielddescr) - self.cache[encoded_pos] = virtual_box if pos_in_frame != -1: self.metainterp.history.record(rop.RESUME_PUT, [virtual_box, @@ -248,9 +154,6 @@ None, None) return virtual_box - def allocate_struct(self, virtual): - return self.metainterp.execute_and_record(rop.NEW, virtual.descr) - def setfield_gc(self, box, encoded_field_pos, fielddescr): field_box = self.get_box_value(-1, -1, encoded_field_pos, fielddescr.kind) diff --git a/rpython/jit/resume/reader.py b/rpython/jit/resume/reader.py --- a/rpython/jit/resume/reader.py +++ b/rpython/jit/resume/reader.py @@ -1,4 +1,6 @@ +from rpython.jit.metainterp.resoperation import rop +from rpython.jit.metainterp.history import ConstInt from rpython.jit.resume import rescode class ResumeFrame(object): @@ -7,13 +9,33 @@ self.jitcode = jitcode self.pc = -1 +class BaseVirtual(object): + pass -class Virtual(object): +class VirtualStruct(BaseVirtual): def __init__(self, pos, descr): self.pos = pos self.fields = {} self.descr = descr + def allocate_box(self, metainterp): + return metainterp.execute_and_record(rop.NEW, self.descr) + + def allocate_direct(self, cpu): + return cpu.bh_new(self.descr) + +class VirtualWithVtable(BaseVirtual): + def __init__(self, pos, const_class): + self.pos = pos + self.const_class = const_class + self.fields = {} + + def allocate_box(self, metainterp): + return metainterp.execute_and_record(rop.NEW_WITH_VTABLE, + ConstInt(self.const_class)) + + def allocate_direct(self, cpu): + return cpu.bh_new_with_vtable(self.const_class) class AbstractResumeReader(object): """ A resume reader that can follow resume until given point. Consult @@ -46,11 +68,19 @@ self.framestack[frame_no].registers[frontend_position] = encoded_pos def resume_new(self, v_pos, descr): - v = Virtual(v_pos, descr) + v = VirtualStruct(v_pos, descr) + self._add_to_virtuals(v, v_pos) + + def resume_new_with_vtable(self, v_pos, c_const_class): + const_class = c_const_class.getint() + v = VirtualWithVtable(v_pos, const_class) + self._add_to_virtuals(v, v_pos) + + def _add_to_virtuals(self, v, v_pos): if v_pos >= len(self.virtuals): self.virtuals += [None] * (len(self.virtuals) - v_pos + 1) self.virtuals[v_pos] = v - + def resume_setfield_gc(self, pos, fieldpos, descr): # XXX optimize fields tag, index = self.decode(pos) @@ -97,11 +127,15 @@ self.resume_put(encoded, frame_pos, pos_in_frame) pos += 5 elif op == rescode.RESUME_NEW: - tag, v_pos = self.decode(self.read_short(pos + 1)) - assert tag == rescode.TAGVIRTUAL + v_pos = self.read_short(pos + 1) descr = self.staticdata.opcode_descrs[self.read_short(pos + 3)] self.resume_new(v_pos, descr) pos += 5 + elif op == rescode.RESUME_NEW_WITH_VTABLE: + v_pos = self.read_short(pos + 1) + const_class = self.consts[self.read_short(pos + 3)] + self.resume_new_with_vtable(v_pos, const_class) + pos += 5 elif op == rescode.RESUME_SETFIELD_GC: structpos = self.read_short(pos + 1) fieldpos = self.read_short(pos + 3) @@ -140,6 +174,10 @@ def resume_new(self, v_pos, descr): self.l.append("%d = resume_new %d" % (v_pos, descr.global_descr_index)) + def resume_new_with_vtable(self, v_pos, c_const_class): + self.l.append("%d = resume_new_with_vtable %d" % (v_pos, + c_const_class.getint())) + def leave_frame(self): self.l.append("leave_frame") diff --git a/rpython/jit/resume/rescode.py b/rpython/jit/resume/rescode.py --- a/rpython/jit/resume/rescode.py +++ b/rpython/jit/resume/rescode.py @@ -64,9 +64,15 @@ not isinstance(const.getint(), Symbolic) and 0 <= const.getint() < 0x4000): return TAGSMALLINT | (const.getint() << 2) + assert len(self.consts) < 0x4000 self.consts.append(const) return TAGCONST | ((len(self.consts) - 1) << 2) + def encode_const_not_small(self, const): + assert len(self.consts) < 0x4000 + self.consts.append(const) + return len(self.consts) - 1 + def resume_set_pc(self, pc): self.write(RESUME_SET_PC) self.write_short(pc) @@ -79,13 +85,13 @@ def resume_new(self, v_pos, descr): self.write(RESUME_NEW) - self.write_short(self.encode(TAGVIRTUAL, v_pos)) + self.write_short(v_pos) # XXX byte virtuals? self.write_short(descr.global_descr_index) def resume_new_with_vtable(self, v_pos, const_class): self.write(RESUME_NEW_WITH_VTABLE) - self.write_short(self.encode(TAGVIRTUAL, v_pos)) - self.write_short(self.encode_const(const_class)) + self.write_short(v_pos) # XXX byte virtuals? + self.write_short(self.encode_const_not_small(const_class)) def resume_setfield_gc(self, structpos, fieldpos, descr): self.write(RESUME_SETFIELD_GC) 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,\ - ConstInt -from rpython.jit.resume.frontend import rebuild_from_resumedata + ConstInt, REF +from rpython.jit.resume.frontend import rebuild_from_resumedata,\ + blackhole_from_resumedata from rpython.jit.resume.rescode import ResumeBytecode, TAGBOX,\ ResumeBytecodeBuilder, TAGCONST, TAGSMALLINT, TAGVIRTUAL, CLEAR_POSITION from rpython.jit.resume.reader import AbstractResumeReader @@ -72,10 +73,42 @@ self.framestack.pop() class MockCPU(object): + def __init__(self): + self.history = [] + def get_int_value(self, frame, index): assert frame == "myframe" return index + 3 + def bh_new(self, descr): + self.history.append(("new", descr)) + return "new" + + def bh_setfield_gc_i(self, struct, intval, fielddescr): + self.history.append(("setfield_gc_i", struct, intval, fielddescr)) + + def bh_setfield_gc_r(self, struct, refval, fielddescr): + self.history.append(("setfield_gc_r", struct, refval, fielddescr)) + + def bh_new_with_vtable(self, const_class): + self.history.append(("new_with_vtable", const_class)) + return "new_with_vtable" + +class MockBlackholeInterp(object): + def __init__(self): + pass + + def setposition(self, jitcode, pos): + self.positions = pos + self.jitcode = jitcode + self.registers_i = [-1] * jitcode.num_regs_i() + self.registers_r = [None] * jitcode.num_regs_r() + +class FakeInterpBuilder(object): + def acquire_interp(self): + self.interp = MockBlackholeInterp() + return self.interp + class RebuildingResumeReader(AbstractResumeReader): def finish(self): res = [] @@ -111,6 +144,7 @@ metainterp = MockMetaInterp() metainterp.staticdata = MockStaticData([jitcode], []) metainterp.cpu = MockCPU() + metainterp.staticdata.cpu = metainterp.cpu inputargs, inplocs = rebuild_from_resumedata(metainterp, "myframe", descr) assert len(metainterp.framestack) == 1 @@ -172,28 +206,63 @@ jitcode1.setup(num_regs_i=0, num_regs_r=1, num_regs_f=0) builder = ResumeBytecodeBuilder() descr = Descr() + const_class = ConstInt(13) descr.global_descr_index = 0 builder.enter_frame(-1, jitcode1) builder.resume_new(0, descr) + builder.resume_new_with_vtable(1, const_class) d2 = Descr() d2.kind = INT d2.global_descr_index = 1 + d3 = Descr() + d3.kind = REF + d3.global_descr_index = 2 builder.resume_setfield_gc(TAGVIRTUAL | (0 << 2), TAGSMALLINT | (1 << 2), d2) + builder.resume_setfield_gc(TAGVIRTUAL | (0 << 2), + TAGVIRTUAL | (1 << 2), d3) + builder.resume_put(TAGVIRTUAL | (0 << 2), 0, 0) rd = builder.build() descr = Descr() - descr.rd_resume_bytecode = ResumeBytecode(rd, []) + descr.rd_resume_bytecode = ResumeBytecode(rd, [const_class]) descr.rd_bytecode_position = len(rd) metainterp = MockMetaInterp() - metainterp.staticdata = MockStaticData([jitcode1], [descr, d2]) + metainterp.staticdata = MockStaticData([jitcode1], [descr, d2, d3]) metainterp.cpu = MockCPU() + metainterp.staticdata.cpu = metainterp.cpu rebuild_from_resumedata(metainterp, "myframe", descr) expected = [(rop.NEW, descr), (rop.SETFIELD_GC, d2, AnyBox(), EqConstInt(1)), + (rop.NEW_WITH_VTABLE, EqConstInt(13)), + (rop.SETFIELD_GC, d3, AnyBox(), AnyBox()), (rop.RESUME_PUT, None, AnyBox(), EqConstInt(0), EqConstInt(0))] - assert metainterp.history == expected + expected2 = [(rop.NEW, descr), + (rop.NEW_WITH_VTABLE, EqConstInt(13)), + (rop.SETFIELD_GC, d3, AnyBox(), AnyBox()), + (rop.SETFIELD_GC, d2, AnyBox(), EqConstInt(1)), + (rop.RESUME_PUT, None, AnyBox(), EqConstInt(0), + EqConstInt(0))] + assert metainterp.history == expected or metainterp.history == expected2 + ib = FakeInterpBuilder() + blackhole_from_resumedata(ib, metainterp.staticdata, + descr, "myframe") + hist = metainterp.cpu.history + dir_expected2 = [ + ("new", descr), + ("new_with_vtable", 13), + ("setfield_gc_r", "new", "new_with_vtable", d3), + ("setfield_gc_i", "new", 1, d2), + ] + dir_expected = [ + ("new", descr), + ("setfield_gc_i", "new", 1, d2), + ("new_with_vtable", 13), + ("setfield_gc_r", "new", "new_with_vtable", d3), + ] + assert hist == dir_expected or hist == dir_expected2 + assert ib.interp.registers_r[0] == "new" def test_reconstructing_resume_reader(self): jitcode1 = JitCode("jitcode") _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit