Commits

Armin Rigo committed 14d1f61

Starting on stmrewrite.py.

Comments (0)

Files changed (7)

pypy/jit/backend/llsupport/gc.py

             from pypy.jit.backend.llsupport.rewrite import GcRewriterAssembler
         else:
             from pypy.jit.backend.llsupport import stmrewrite
-            GcRewriterAssembler = stmrewrite.GcStmReviewerAssembler
+            GcRewriterAssembler = stmrewrite.GcStmRewriterAssembler
         rewriter = GcRewriterAssembler(self, cpu)
         newops = rewriter.rewrite(operations)
         # record all GCREFs, because the GC (or Boehm) cannot see them and
     def _initialize_for_tests(self):
         self.layoutbuilder = None
         self.fielddescr_tid = AbstractDescr()
-        self.max_size_of_young_obj = 1000
+        if self.stm:
+            self.max_size_of_young_obj = None
+        else:
+            self.max_size_of_young_obj = 1000
         self.GCClass = None
 
     def _check_valid_gc(self):
             funcptr(llmemory.cast_ptr_to_adr(gcref_struct))
 
     def can_use_nursery_malloc(self, size):
-        return (self.max_size_of_young_obj is None or
+        return (self.max_size_of_young_obj is not None and
                 size < self.max_size_of_young_obj)
 
     def has_write_barrier_class(self):

pypy/jit/backend/llsupport/rewrite.py

         self.cpu = cpu
         self.newops = []
         self.known_lengths = {}
-        self.recent_mallocs = {}     # set of variables
+        self.recent_mallocs = set()     # set of variables
 
     def rewrite(self, operations):
         # we can only remember one malloc since the next malloc can possibly
             if op.is_malloc():
                 self.handle_malloc_operation(op)
                 continue
-            elif op.can_malloc():
+            elif op.is_call():
                 self.emitting_an_operation_that_can_collect()
             elif op.getopnum() == rop.LABEL:
                 self.emitting_an_operation_that_can_collect()
         op = ResOperation(rop.CALL_MALLOC_GC, args, v_result, descr)
         self.newops.append(op)
         # mark 'v_result' as freshly malloced
-        self.recent_mallocs[v_result] = None
+        self.recent_mallocs.add(v_result)
 
     def gen_malloc_fixedsize(self, size, typeid, v_result):
         """Generate a CALL_MALLOC_GC(malloc_fixedsize_fn, ...).
         self.newops.append(op)
         self._previous_size = size
         self._v_last_malloced_nursery = v_result
-        self.recent_mallocs[v_result] = None
+        self.recent_mallocs.add(v_result)
         return True
 
     def gen_initialize_tid(self, v_newgcobj, tid):

pypy/jit/backend/llsupport/stmrewrite.py

+from pypy.jit.backend.llsupport.rewrite import GcRewriterAssembler
+from pypy.jit.metainterp.resoperation import ResOperation, rop
+from pypy.jit.metainterp.history import BoxPtr, ConstPtr
+
+
+class GcStmRewriterAssembler(GcRewriterAssembler):
+    # This class performs the same rewrites as its base class,
+    # plus the rewrites described in stm.txt.
+
+    def __init__(self, *args):
+        GcRewriterAssembler.__init__(self, *args)
+        self.known_local = set()    # set of variables
+
+    def rewrite(self, operations):
+        # overridden method from parent class
+        #
+        for op in operations:
+            if op.getopnum() == rop.DEBUG_MERGE_POINT:
+                continue
+            # ----------  mallocs  ----------
+            if op.is_malloc():
+                self.handle_malloc_operation(op)
+                continue
+            # ----------  setfields  ----------
+            if op.getopnum() in (rop.SETFIELD_GC,
+                                 rop.SETARRAYITEM_GC,
+                                 rop.SETINTERIORFIELD_GC):
+                self.handle_write_barrier(op)
+                continue
+            # ----------  calls, labels  ----------
+            if op.is_call() or op.getopnum() == rop.LABEL:
+                self.known_local.clear()
+            # ----------
+            self.newops.append(op)
+        return self.newops
+
+
+    def gen_write_barrier(self, v_base):
+        assert isinstance(v_base, BoxPtr)
+        if v_base in self.known_local:
+            return    # no write barrier needed
+        write_barrier_descr = self.gc_ll_descr.write_barrier_descr
+        args = [v_base, self.c_zero]
+        self.newops.append(ResOperation(rop.COND_CALL_GC_WB, args, None,
+                                        descr=write_barrier_descr))
+        self.known_local.add(v_base)
+
+    def unconstifyptr(self, v):
+        if isinstance(v, ConstPtr):
+            v_in = v
+            v_out = BoxPtr()
+            self.newops.append(ResOperation(rop.SAME_AS, [v_in], v_out))
+            v = v_out
+        assert isinstance(v, BoxPtr)
+        return v
+
+    def handle_write_barrier(self, op):
+        self.gen_write_barrier(self.unconstifyptr(op.getarg(0)))
+        self.newops.append(op)
+
+    def handle_malloc_operation(self, op):
+        GcRewriterAssembler.handle_malloc_operation(self, op)
+        self.known_local.add(op.result)

pypy/jit/backend/llsupport/test/test_rewrite.py

             namespace[funcname + '_descr'] = getattr(self.gc_ll_descr,
                                                      '%s_descr' % funcname)
         #
-        ops = parse(frm_operations, namespace=namespace)
+        ops = parse(frm_operations, namespace=namespace,
+                    invent_fail_descr=False)
         expected = parse(to_operations % Evaluator(namespace),
-                         namespace=namespace)
+                         namespace=namespace,
+                         invent_fail_descr=False)
         operations = self.gc_ll_descr.rewrite_assembler(self.cpu,
                                                         ops.operations,
                                                         [])

pypy/jit/backend/llsupport/test/test_stmrewrite.py

+from pypy.jit.backend.llsupport.descr import *
 from pypy.jit.backend.llsupport.gc import *
 from pypy.jit.metainterp.gc import get_description
 from pypy.jit.backend.llsupport.test.test_rewrite import RewriteTests
             setfield_gc(p1, p2, descr=tzdescr)
             jump()
         """, """
+            [p1, p2]
+            cond_call_gc_wb(p1, 0, descr=wbdescr)
+            setfield_gc(p1, p2, descr=tzdescr)
+            jump()
+        """)
+
+    def test_rewrite_setfield_gc_on_local(self):
+        self.check_rewrite("""
             [p1]
-            cond_call_gc_wb(p1, 0, descr=wbdescr)
-            setfield_gc(p2, p2, descr=tzdescr)
-            jump()
+            p2 = new(descr=tdescr)
+            setfield_gc(p2, p1, descr=tzdescr)
+            jump(p2)
+        """, """
+            [p1]
+            p2 = call_malloc_gc(ConstClass(malloc_big_fixedsize),    \
+                                %(tdescr.size)d, %(tdescr.tid)d, \
+                                descr=malloc_big_fixedsize_descr)
+            setfield_gc(p2, p1, descr=tzdescr)
+            jump(p2)
         """)
 
     def test_rewrite_unrelated_setfield_gcs(self):
             jump(p1)
         """)
 
+    def test_remove_debug_merge_point(self):
+        self.check_rewrite("""
+            [i1, i2]
+            debug_merge_point(i1, i2)
+            jump()
+        """, """
+            [i1, i2]
+            jump()
+        """)
+
     def test_ignore_some_operations(self):
         oplist = [
             "guard_true(i1) [i2]",    # all guards
             "i3 = force_token()",
             "i3 = read_timestamp()",
             "i3 = mark_opaque_ptr(p1)",
-            "debug_merge_point(i1, i2)",
             "jit_debug(i1, i2)",
             "keepalive(i1)",
             "i3 = int_sub_ovf(i1, i2)",   # is_ovf operations
             jump(p2)
         """)
 
+    def test_rewrite_getfield_gc_on_local_2(self):
+        self.check_rewrite("""
+            [p1]
+            p1 = new(descr=tdescr)
+            p2 = getfield_gc(p1, descr=tzdescr)
+            jump(p2)
+        """, """
+            [p1]
+            p1 = call_malloc_gc(ConstClass(malloc_fixedsize),    \
+                                %(tdescr.size)d, %(tdescr.tid)d, \
+                                descr=malloc_fixedsize_descr)
+            p2 = getfield_gc(p1, descr=tzdescr)
+            jump(p2)
+        """)
+
     def test_rewrite_getfield_gc_on_future_local(self):
         self.check_rewrite("""
             [p1]

pypy/jit/metainterp/resoperation.py

         return rop._CANRAISE_FIRST <= self.getopnum() <= rop._CANRAISE_LAST
 
     def is_malloc(self):
-        # a slightly different meaning from can_malloc
         return rop._MALLOC_FIRST <= self.getopnum() <= rop._MALLOC_LAST
 
-    def can_malloc(self):
-        return self.is_call() or self.is_malloc()
-
     def is_call(self):
         return rop._CALL_FIRST <= self.getopnum() <= rop._CALL_LAST
 

pypy/jit/metainterp/test/test_resoperation.py

     assert op.result == 'c'
     assert op.getdescr() is mydescr
 
-def test_can_malloc():
+def test_is_malloc():
     mydescr = AbstractDescr()
-    assert rop.ResOperation(rop.rop.NEW, [], 'b').can_malloc()
+    assert rop.ResOperation(rop.rop.NEW, [], 'b').is_malloc()
     call = rop.ResOperation(rop.rop.CALL, ['a', 'b'], 'c', descr=mydescr)
-    assert call.can_malloc()
-    assert not rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 'c').can_malloc()
+    assert not call.is_malloc()
+    assert not rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 'c').is_malloc()
 
 def test_get_deep_immutable_oplist():
     ops = [rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 'c')]