Author: Armin Rigo <[email protected]>
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
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit