[pypy-commit] pypy gc_no_cleanup_nursery: Backout the changes, come back to the previous approach
fijal
noreply at buildbot.pypy.org
Thu Sep 11 20:01:34 CEST 2014
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: gc_no_cleanup_nursery
Changeset: r73466:1066bc5225af
Date: 2014-09-11 11:36 -0600
http://bitbucket.org/pypy/pypy/changeset/1066bc5225af/
Log: Backout the changes, come back to the previous approach
diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -643,6 +643,20 @@
array = lltype.malloc(arraydescr.A, length)
return lltype.cast_opaque_ptr(llmemory.GCREF, array)
+ def bh_clear_array_contents(self, a, descr):
+ a = support.cast_arg(lltype.Ptr(descr.A), a)
+ ITEM = descr.A.OF
+ array = a._obj
+ if isinstance(ITEM, lltype.Struct):
+ for i in xrange(array.getlength()):
+ for name, FIELD in ITEM._flds.iteritems():
+ null = FIELD._defl()
+ setattr(array.getitem(i), name, null)
+ else:
+ null = ITEM._defl()
+ for i in xrange(array.getlength()):
+ array.setitem(i, null)
+
def bh_classof(self, struct):
struct = lltype.cast_opaque_ptr(rclass.OBJECTPTR, struct)
result_adr = llmemory.cast_ptr_to_adr(struct.typeptr)
diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py
--- a/rpython/jit/backend/llsupport/llmodel.py
+++ b/rpython/jit/backend/llsupport/llmodel.py
@@ -591,6 +591,14 @@
def bh_new(self, sizedescr):
return self.gc_ll_descr.gc_malloc(sizedescr)
+ def bh_clear_array_contents(self, ref, arraydescr):
+ ofs, size, _ = self.unpack_arraydescr_size(arraydescr)
+ arraysize = self.bh_arraylen_gc(ref, arraydescr)
+ totalsize = size * arraysize
+ adr = rffi.cast(lltype.Signed, ref) + ofs
+ self.gc_ll_descr.memset_ptr(adr, rffi.cast(rffi.INT, 0),
+ rffi.cast(rffi.SIZE_T, totalsize))
+
def bh_new_with_vtable(self, vtable, sizedescr):
res = self.gc_ll_descr.gc_malloc(sizedescr)
if self.vtable_offset is not None:
diff --git a/rpython/jit/backend/llsupport/rewrite.py b/rpython/jit/backend/llsupport/rewrite.py
--- a/rpython/jit/backend/llsupport/rewrite.py
+++ b/rpython/jit/backend/llsupport/rewrite.py
@@ -59,6 +59,10 @@
if op.is_malloc():
self.handle_malloc_operation(op)
continue
+ elif op.getopnum() == rop.CLEAR_ARRAY_CONTENTS:
+ if not self.gc_ll_descr.malloc_zero_filled:
+ self.handle_clear_array_contents(op)
+ continue
elif op.can_malloc():
self.emitting_an_operation_that_can_collect()
elif op.getopnum() == rop.LABEL:
@@ -157,6 +161,26 @@
else:
raise NotImplementedError(op.getopname())
+ def handle_clear_array_contents(self, op):
+ # XXX this maybe should go to optimizer, so we can remove extra ops?
+ arraydescr = op.getdescr()
+ ofs, size, _ = self.cpu.unpack_arraydescr_size(arraydescr)
+ v_arr = op.getarg(0)
+ v_arr_plus_ofs = BoxInt()
+ v_arrsize = BoxInt()
+ v_totalsize = BoxInt()
+ gcdescr = self.gc_ll_descr
+ ops = [
+ ResOperation(rop.INT_ADD, [v_arr, ConstInt(size)], v_arr_plus_ofs),
+ ResOperation(rop.ARRAYLEN_GC, [v_arr], v_arrsize, descr=arraydescr),
+ ResOperation(rop.INT_MUL, [v_arrsize, ConstInt(size)], v_totalsize),
+ ResOperation(rop.CALL, [ConstInt(gcdescr.memset_ptr_as_int),
+ v_arr_plus_ofs,
+ ConstInt(0), v_totalsize], None,
+ descr=gcdescr.memset_descr),
+ ]
+ self.newops.extend(ops)
+
def gen_malloc_frame(self, frame_info, frame, size_box):
descrs = self.gc_ll_descr.getframedescrs(self.cpu)
if self.gc_ll_descr.kind == 'boehm':
diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -4439,3 +4439,21 @@
res = self.execute_operation(rop.CAST_FLOAT_TO_SINGLEFLOAT,
[boxfloat(12.5)], 'int')
assert res.getint() == struct.unpack("I", struct.pack("f", 12.5))[0]
+
+ def test_clear_array_contents(self):
+ from rpython.jit.backend.llsupport.llmodel import AbstractLLCPU
+ if not isinstance(self.cpu, AbstractLLCPU):
+ py.test.skip("pointless test on non-asm")
+ oldval = self.cpu.gc_ll_descr.malloc_zero_filled
+ self.cpu.gc_ll_descr.malloc_zero_filled = False
+ try:
+ A = lltype.GcArray(lltype.Signed)
+ a = lltype.malloc(A, 3)
+ a[1] = 13
+ descr = self.cpu.arraydescrof(A)
+ ref = lltype.cast_opaque_ptr(llmemory.GCREF, a)
+ self.execute_operation(rop.CLEAR_ARRAY_CONTENTS,
+ [BoxPtr(ref)], 'void', descr=descr)
+ assert a[1] == 0
+ finally:
+ self.cpu.gc_ll_descr.malloc_zero_filled = oldval
diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -315,7 +315,8 @@
self.assembler.mc.mark_op(op)
self.rm.position = i
self.xrm.position = i
- if op.has_no_side_effect() and op.result not in self.longevity:
+ if (op.has_no_side_effect() and op.result not in self.longevity
+ and op.opnum != rop.CLEAR_ARRAY_CONTENTS):
i += 1
self.possibly_free_vars_for_op(op)
continue
diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -612,8 +612,39 @@
# XXX only strings or simple arrays for now
ARRAY = op.args[0].value
arraydescr = self.cpu.arraydescrof(ARRAY)
- return SpaceOperation('new_array', [op.args[2], arraydescr],
- op.result)
+ op1 = SpaceOperation('new_array', [op.args[2], arraydescr],
+ op.result)
+ if self._has_gcptrs_in(ARRAY):
+ return self.zero_contents([op1], op.result, ARRAY,
+ only_gc_pointers=True)
+ if op.args[1].value.get('zero', False):
+ return self.zero_contents([op1], op.result, ARRAY)
+ return op1
+
+ def zero_contents(self, ops, v, TYPE, only_gc_pointers=False):
+ if isinstance(TYPE, lltype.Struct):
+ for name, FIELD in TYPE._flds.iteritems():
+ if (not only_gc_pointers or
+ isinstance(FIELD, lltype.Ptr) and FIELD._needsgc()):
+ c_name = Constant(name, lltype.Void)
+ c_null = Constant(FIELD._defl(), FIELD)
+ op = SpaceOperation('setfield', [v, c_name, c_null],
+ None)
+ self.extend_with(ops, self.rewrite_op_setfield(op,
+ override_type=TYPE))
+ elif isinstance(FIELD, lltype.Struct):
+ # substruct
+ self.zero_contents(ops, v, FIELD,
+ only_gc_pointers=only_gc_pointers)
+ elif isinstance(TYPE, lltype.Array):
+ arraydescr = self.cpu.arraydescrof(TYPE)
+ ops.append(SpaceOperation('clear_array_contents',
+ [v, arraydescr], None))
+ else:
+ raise TypeError("Expected struct or array, got '%r'", (TYPE,))
+ if len(ops) == 1:
+ return ops[0]
+ return ops
def extend_with(self, l, ops):
if ops is None:
@@ -899,7 +930,28 @@
else:
opname = 'new'
sizedescr = self.cpu.sizeof(STRUCT)
- return SpaceOperation(opname, [sizedescr], op.result)
+ op1 = SpaceOperation(opname, [sizedescr], op.result)
+ if true_zero:
+ return self.zero_contents([op1], op.result, STRUCT)
+ if self._has_gcptrs_in(STRUCT):
+ return self.zero_contents([op1], op.result, STRUCT,
+ only_gc_pointers=True)
+ return op1
+
+ def _has_gcptrs_in(self, STRUCT):
+ if isinstance(STRUCT, lltype.Array):
+ ITEM = STRUCT.OF
+ if isinstance(ITEM, lltype.Struct):
+ STRUCT = ITEM
+ else:
+ return isinstance(ITEM, lltype.Ptr) and ITEM._needsgc()
+ for FIELD in STRUCT._flds.values():
+ if isinstance(FIELD, lltype.Ptr) and FIELD._needsgc():
+ return True
+ elif isinstance(FIELD, lltype.Struct):
+ if self._has_gcptrs_in(FIELD):
+ return True
+ return False
def rewrite_op_getinteriorarraysize(self, op):
# only supports strings and unicodes
@@ -1625,6 +1677,8 @@
v.concretetype = lltype.Signed
ops.append(SpaceOperation('int_force_ge_zero', [v_length], v))
ops.append(SpaceOperation('new_array', [v, arraydescr], op.result))
+ if self._has_gcptrs_in(op.result.concretetype.TO):
+ self.zero_contents(ops, op.result, op.result.concretetype.TO)
return ops
def do_fixed_list_len(self, op, args, arraydescr):
diff --git a/rpython/jit/codewriter/test/test_jtransform.py b/rpython/jit/codewriter/test/test_jtransform.py
--- a/rpython/jit/codewriter/test/test_jtransform.py
+++ b/rpython/jit/codewriter/test/test_jtransform.py
@@ -529,6 +529,46 @@
assert op1.opname == 'new'
assert op1.args == [('sizedescr', S)]
+def test_malloc_new_zero():
+ SS = lltype.GcStruct('SS')
+ S = lltype.GcStruct('S', ('x', lltype.Ptr(SS)))
+ v = varoftype(lltype.Ptr(S))
+ op = SpaceOperation('malloc', [Constant(S, lltype.Void),
+ Constant({'flavor': 'gc'}, lltype.Void)], v)
+ op1, op2 = Transformer(FakeCPU()).rewrite_operation(op)
+ assert op1.opname == 'new'
+ assert op1.args == [('sizedescr', S)]
+ assert op2.opname == 'setfield_gc_r'
+ assert op2.args[0] == v
+
+def test_malloc_new_zero_2():
+ S = lltype.GcStruct('S', ('x', lltype.Signed))
+ v = varoftype(lltype.Ptr(S))
+ op = SpaceOperation('malloc', [Constant(S, lltype.Void),
+ Constant({'flavor': 'gc',
+ 'zero': True}, lltype.Void)], v)
+ op1, op2 = Transformer(FakeCPU()).rewrite_operation(op)
+ assert op1.opname == 'new'
+ assert op1.args == [('sizedescr', S)]
+ assert op2.opname == 'setfield_gc_i'
+ assert op2.args[0] == v
+
+def test_malloc_new_zero_nested():
+ S0 = lltype.GcStruct('S0')
+ S = lltype.Struct('S', ('x', lltype.Ptr(S0)))
+ S2 = lltype.GcStruct('S2', ('parent', S),
+ ('xx', lltype.Ptr(S0)))
+ v = varoftype(lltype.Ptr(S2))
+ op = SpaceOperation('malloc', [Constant(S2, lltype.Void),
+ Constant({'flavor': 'gc'}, lltype.Void)], v)
+ op1, op2, op3 = Transformer(FakeCPU()).rewrite_operation(op)
+ assert op1.opname == 'new'
+ assert op1.args == [('sizedescr', S2)]
+ assert op2.opname == 'setfield_gc_r'
+ assert op2.args[0] == v
+ assert op3.opname == 'setfield_gc_r'
+ assert op3.args[0] == v
+
def test_malloc_new_with_vtable():
vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
S = lltype.GcStruct('S', ('parent', rclass.OBJECT))
@@ -1026,6 +1066,20 @@
assert op1.args == [v1]
assert op1.result == v2
+def test_malloc_varsize_zero():
+ c_A = Constant(lltype.GcArray(lltype.Signed), lltype.Void)
+ c_flags = Constant({"flavor": "gc"}, lltype.Void)
+ v1 = varoftype(lltype.Signed)
+ v2 = varoftype(c_A.value)
+ op = SpaceOperation('malloc_varsize', [c_A, c_flags, v1], v2)
+ op1 = Transformer(FakeCPU()).rewrite_operation(op)
+ assert op1.opname == 'new_array'
+ c_flags = Constant({"flavor": "gc", "zero": True}, lltype.Void)
+ op = SpaceOperation('malloc_varsize', [c_A, c_flags, v1], v2)
+ op1, op2 = Transformer(FakeCPU()).rewrite_operation(op)
+ assert op1.opname == 'new_array'
+ assert op2.opname == 'clear_array_contents'
+
def test_str_concat():
# test that the oopspec is present and correctly transformed
PSTR = lltype.Ptr(rstr.STR)
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
@@ -1345,6 +1345,10 @@
vtable = heaptracker.descr2vtable(cpu, descr)
return cpu.bh_new_with_vtable(vtable, descr)
+ @arguments("cpu", "r", "d")
+ def bhimpl_clear_array_contents(cpu, ref, descr):
+ cpu.bh_clear_array_contents(ref, descr)
+
@arguments("cpu", "r", returns="i")
def bhimpl_guard_class(cpu, struct):
return cpu.bh_classof(struct)
diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py
--- a/rpython/jit/metainterp/executor.py
+++ b/rpython/jit/metainterp/executor.py
@@ -335,6 +335,7 @@
rop.CALL_MALLOC_NURSERY,
rop.CALL_MALLOC_NURSERY_VARSIZE,
rop.CALL_MALLOC_NURSERY_VARSIZE_FRAME,
+ rop.CLEAR_ARRAY_CONTENTS,
rop.LABEL,
): # list of opcodes never executed by pyjitpl
continue
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -5461,6 +5461,17 @@
"""
self.optimize_loop(ops, expected)
+ def test_virtual_clear_array_contents(self):
+ ops = """
+ []
+ p0 = new_array(2, descr=arraydescr)
+ clear_array_contents(p0, descr=arraydescr)
+ """
+ expected = """
+ []
+ """
+ self.optimize_loop(ops, expected)
+
class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin):
pass
diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py
--- a/rpython/jit/metainterp/optimizeopt/virtualize.py
+++ b/rpython/jit/metainterp/optimizeopt/virtualize.py
@@ -662,6 +662,12 @@
else:
self.emit_operation(op)
+ def optimize_CLEAR_ARRAY_CONTENTS(self, op):
+ v = self.getvalue(op.getarg(0))
+ if v.is_virtual():
+ return
+ self.emit_operation(op)
+
def optimize_CALL(self, op):
effectinfo = op.getdescr().get_extra_info()
if effectinfo.oopspecindex == EffectInfo.OS_RAW_MALLOC_VARSIZE_CHAR:
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
@@ -396,6 +396,10 @@
def opimpl_new(self, sizedescr):
return self.metainterp.execute_new(sizedescr)
+ @arguments("box", "descr")
+ def opimpl_clear_array_contents(self, box, descr):
+ self.metainterp.execute_and_record(rop.CLEAR_ARRAY_CONTENTS, descr, box)
+
@arguments("descr")
def opimpl_new_with_vtable(self, sizedescr):
cpu = self.metainterp.cpu
diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -492,6 +492,9 @@
'MARK_OPAQUE_PTR/1b',
# this one has no *visible* side effect, since the virtualizable
# must be forced, however we need to execute it anyway
+ 'CLEAR_ARRAY_CONTENTS/1d',
+ # this one does not *really* have a side effect since it's equivalent
+ # to array just coming zeroed
'_NOSIDEEFFECT_LAST', # ----- end of no_side_effect operations -----
'INCREMENT_DEBUG_COUNTER/1',
More information about the pypy-commit
mailing list