Author: Armin Rigo <ar...@tunes.org> Branch: op_malloc_gc Changeset: r49508:a85153701bb6 Date: 2011-11-10 21:32 +0100 http://bitbucket.org/pypy/pypy/changeset/a85153701bb6/
Log: Attempt to collapse several NEW-like operations into a single simpler MALLOC_GC operation: starting... diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -672,6 +672,7 @@ self.WB_ARRAY_FUNCPTR = lltype.Ptr(lltype.FuncType( [llmemory.Address, lltype.Signed, llmemory.Address], lltype.Void)) self.write_barrier_descr = WriteBarrierDescr(self) + self.fielddescr_tid = self.write_barrier_descr.fielddescr_tid # def malloc_array(itemsize, tid, num_elem): type_id = llop.extract_ushort(llgroup.HALFWORD, tid) @@ -809,17 +810,52 @@ newops = [] known_lengths = {} # we can only remember one malloc since the next malloc can possibly - # collect - last_malloc = None + # collect; but we can try to collapse several known-size mallocs into + # one, both for performance and to reduce the number of write + # barriers. We do this on each "basic block" of operations, which in + # this case means between CALLs or unknown-size mallocs. + op_malloc_gc = None + v_last_malloc = None + previous_size = -1 + current_mallocs = {} + # for op in operations: if op.getopnum() == rop.DEBUG_MERGE_POINT: continue # ---------- record the ConstPtrs ---------- self.record_constptrs(op, gcrefs_output_list) + # ---------- fold the NEWxxx operations into MALLOC_GC ---------- if op.is_malloc(): - last_malloc = op.result + if op.getopnum() == rop.NEW: + descr = op.getdescr() + assert isinstance(descr, BaseSizeDescr) + if op_malloc_gc is None: + # it is the first we see: emit MALLOC_GC + op = ResOperation(rop.MALLOC_GC, + [ConstInt(descr.size)], + op.result) + op_malloc_gc = op + else: + # already a MALLOC_GC: increment its total size + total_size = op_malloc_gc.getarg(0).getint() + total_size += descr.size + op_malloc_gc.setarg(0, ConstInt(total_size)) + op = ResOperation(rop.INT_ADD, + [v_last_malloc, + ConstInt(previous_size)], + op.result) + previous_size = descr.size + v_last_malloc = op.result + newops.append(op) + # NEW: add a SETFIELD to initialize the GC header + op = ResOperation(rop.SETFIELD_GC, + [op.result, ConstInt(descr.tid)], + None, descr=self.fielddescr_tid) + newops.append(op) + continue + op_last_malloc = op elif op.can_malloc(): - last_malloc = None + op_last_malloc = None # ---------- write barrier for SETFIELD_GC ---------- if op.getopnum() == rop.SETFIELD_GC: val = op.getarg(0) diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py --- a/pypy/jit/backend/llsupport/test/test_gc.py +++ b/pypy/jit/backend/llsupport/test/test_gc.py @@ -570,6 +570,68 @@ assert operations[1].getarg(2) == v_value assert operations[1].getdescr() == array_descr + def test_rewrite_assembler_new_to_malloc(self): + self.gc_ll_descr.translate_support_code = False + try: + S = lltype.GcStruct('S', ('x', lltype.Signed)) + sdescr = get_size_descr(self.gc_ll_descr, S) + sdescr.tid = 1234 + finally: + self.gc_ll_descr.translate_support_code = True + tiddescr = self.gc_ll_descr.fielddescr_tid + ops = parse(""" + [p1] + p0 = new(descr=sdescr) + jump() + """, namespace=locals()) + expected = parse(""" + [p1] + p0 = malloc_gc(%d) + setfield_gc(p0, 1234, descr=tiddescr) + jump() + """ % (sdescr.size,), namespace=locals()) + operations = get_deep_immutable_oplist(ops.operations) + operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) + equaloplists(operations, expected.operations) + + def test_rewrite_assembler_new3_to_malloc(self): + self.gc_ll_descr.translate_support_code = False + try: + S = lltype.GcStruct('S', ('x', lltype.Signed)) + sdescr = get_size_descr(self.gc_ll_descr, S) + sdescr.tid = 1234 + T = lltype.GcStruct('T', ('y', lltype.Signed), + ('z', lltype.Signed)) + tdescr = get_size_descr(self.gc_ll_descr, T) + tdescr.tid = 5678 + finally: + self.gc_ll_descr.translate_support_code = True + tiddescr = self.gc_ll_descr.fielddescr_tid + ops = parse(""" + [] + p0 = new(descr=sdescr) + p1 = new(descr=tdescr) + p2 = new(descr=sdescr) + jump() + """, namespace=locals()) + expected = parse(""" + [] + p0 = malloc_gc(%d) + setfield_gc(p0, 1234, descr=tiddescr) + p1 = int_add(p0, %d) + setfield_gc(p1, 5678, descr=tiddescr) + p2 = int_add(p1, %d) + setfield_gc(p2, 1234, descr=tiddescr) + jump() + """ % (sdescr.size + tdescr.size + sdescr.size, + sdescr.size, + tdescr.size), namespace=locals()) + operations = get_deep_immutable_oplist(ops.operations) + operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) + equaloplists(operations, expected.operations) + def test_rewrite_assembler_initialization_store(self): S = lltype.GcStruct('S', ('parent', OBJECT), ('x', lltype.Signed)) diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py --- a/pypy/jit/metainterp/executor.py +++ b/pypy/jit/metainterp/executor.py @@ -344,6 +344,7 @@ rop.SETINTERIORFIELD_RAW, rop.CALL_RELEASE_GIL, rop.QUASIIMMUT_FIELD, + rop.MALLOC_GC, ): # list of opcodes never executed by pyjitpl continue raise AssertionError("missing %r" % (key,)) diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -470,6 +470,7 @@ 'NEW_ARRAY/1d', 'NEWSTR/1', 'NEWUNICODE/1', + 'MALLOC_GC/1', # added by llsupport/gc: GC malloc of ConstInt bytes '_MALLOC_LAST', 'FORCE_TOKEN/0', 'VIRTUAL_REF/2', # removed before it's passed to the backend _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit