[pypy-commit] pypy stm-thread-2: in-progress: fixing the JIT

arigo noreply at buildbot.pypy.org
Tue Sep 11 14:35:39 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: stm-thread-2
Changeset: r57274:31237d8ba2d4
Date: 2012-09-11 14:01 +0200
http://bitbucket.org/pypy/pypy/changeset/31237d8ba2d4/

Log:	in-progress: fixing the JIT

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
@@ -583,9 +583,10 @@
 
 
 class WriteBarrierDescr(AbstractDescr):
-    def __init__(self, gc_ll_descr):
+    def __init__(self, gc_ll_descr, stmcat=None):
         self.llop1 = gc_ll_descr.llop1
-        self.returns_modified_object = gc_ll_descr.stm
+        self.stmcat = stmcat
+        self.returns_modified_object = (stmcat is not None)
         if not self.returns_modified_object:
             self.WB_FUNCPTR = lltype.Ptr(lltype.FuncType(
                 [llmemory.Address], lltype.Void))
@@ -597,7 +598,10 @@
         GCClass = gc_ll_descr.GCClass
         if GCClass is None:     # for tests
             return
-        self.jit_wb_if_flag = GCClass.JIT_WB_IF_FLAG
+        if self.stmcat is None:
+            self.jit_wb_if_flag = GCClass.JIT_WB_IF_FLAG
+        else:
+            self.jit_wb_if_flag, cat = self.stmcat
         self.jit_wb_if_flag_byteofs, self.jit_wb_if_flag_singlebyte = (
             self.extract_flag_byte(self.jit_wb_if_flag))
         #
@@ -614,9 +618,21 @@
         else:
             self.jit_wb_cards_set = 0
 
+    def repr_of_descr(self):
+        if self.stmcat is None:
+            return 'wbdescr'
+        else:
+            _, cat = self.stmcat
+            return cat
+
+    def __repr__(self):
+        return '<WriteBarrierDescr %r>' % (self.repr_of_descr(),)
+
     def extract_flag_byte(self, flag_word):
         # if convenient for the backend, we compute the info about
         # the flag as (byte-offset, single-byte-flag).
+        if flag_word == 0:
+            return (0, 0)
         import struct
         value = struct.pack(lltype.SignedFmt, flag_word)
         assert value.count('\x00') == len(value) - 1    # only one byte is != 0
@@ -624,16 +640,20 @@
         while value[i] == '\x00': i += 1
         return (i, struct.unpack('b', value[i])[0])
 
-    def get_write_barrier_fn(self, cpu, returns_modified_object=False):
-        # must pass in 'self.returns_modified_object', to make sure that
+    def get_write_barrier_fn(self, cpu, stm=False):
+        # must pass in 'self.stm', to make sure that
         # the callers are fixed for this case
-        assert returns_modified_object == self.returns_modified_object
-        if returns_modified_object:
+        assert stm == self.returns_modified_object
+        llop1 = self.llop1
+        if self.returns_modified_object:
             FUNCTYPE = self.WB_FUNCPTR_MOD
+            _, cat = self.stmcat
+            assert cat(stm) == 3 and cat[1] == '2'      # "x2y"
+            funcptr = llop1.get_write_barrier_failing_case(FUNCTYPE,
+                                                           cat[0], cat[2])
         else:
             FUNCTYPE = self.WB_FUNCPTR
-        llop1 = self.llop1
-        funcptr = llop1.get_write_barrier_failing_case(FUNCTYPE)
+            funcptr = llop1.get_write_barrier_failing_case(FUNCTYPE)
         funcaddr = llmemory.cast_ptr_to_adr(funcptr)
         return cpu.cast_adr_to_int(funcaddr)
 
@@ -735,7 +755,13 @@
         self.fielddescr_tid = get_field_descr(self, self.GCClass.HDR, 'tid')
 
     def _setup_write_barrier(self):
-        self.write_barrier_descr = WriteBarrierDescr(self)
+        if self.stm:
+            from pypy.rpython.memory.gc import stmgc
+            self.P2Wdescr = WriteBarrierDescr(self,
+                                (stmgc.GCFLAG_NOT_WRITTEN, 'P2W'))
+            self.write_barrier_descr = "wbdescr: do not use"
+        else:
+            self.write_barrier_descr = WriteBarrierDescr(self)
 
     def _make_functions(self, really_not_translated):
         from pypy.rpython.memory.gctypelayout import check_typeid
diff --git a/pypy/jit/backend/llsupport/stm.txt b/pypy/jit/backend/llsupport/stm.txt
deleted file mode 100644
--- a/pypy/jit/backend/llsupport/stm.txt
+++ /dev/null
@@ -1,58 +0,0 @@
-stm support
------------    
-
-Any SETFIELD_GC, SETARRAYITEM_GC, SETINTERIORFIELD_GC must be done on a
-local object.  The operation that forces an object p1 to be local is
-COND_CALL_GC_WB(p1, 0, descr=wbdescr).  When we have stm, this
-COND_CALL_GC_WB is a bit special because if p1 is global, it *replaces*
-its value with the local copy (by changing the register's value and
-patching the stack location if any).  It's still conceptually the same
-object, but the pointer is different.
-
-GETFIELD_GC & friends are more complex.
-
-The fast case is if we also see a write to the same object.  In this
-case we know that the object will have a local copy anyway, even if the
-write is done after the read (we ignore the rare case that a guard may
-fail inbetween).  So in this case we use the same rule as for
-SETFIELD_GC.
-
-The slow case is where we need to read the global object in-place.
-We insert STM_READ_BEFORE() before and STM_READ_AFTER() after, and
-between these two operations there can be only (one or several) reads
-from one object: GETFIELD_GC, GETARRAYITEM_GC, GETINTERIORFIELD_GC,
-COPYSTRCONTENT, COPYUNICODECONTENT.  We need to be careful here because
-STM_READ_AFTER might jump back to STM_READ_BEFORE.  So we must somehow
-precompute how many spills we will need to do, and do them before
-entering the STM_READ_BEFORE.  As a first approximation, we can ensure
-that all registers are spilled before STM_READ_BEFORE.
-
-STM_READ_BEFORE():
-
-    - if (p->flags & GCFLAG_GLOBAL == 0), ovt = p->version
-
-    - else ovt = (call a helper function "ll_stm_read_before")
-
-ll_stm_read_before():
-
-    - if ((p->flags & GCFLAG_WAS_COPIED) != 0 && local_copy_exists(p))
-        replace p with its local copy in the caller (register and stack)
-        return p->version
-
-    - load the thread-local global d = thread_descriptor
-
-    - ovt = p->version
-
-    - if (ovt is locked or newer than d->start_time)
-        call handle_spinloop_or_validation(ovt)
-        jump back to reading 'ovt' above
-
-    - if (!is_inevitable(d))
-        oreclist_insert_if_not_already(d->reads, p)
-
-    - return ovt
-
-STM_READ_AFTER():
-
-    - if (p->version != ovt)
-        jump back to STM_READ_BEFORE
diff --git a/pypy/jit/backend/llsupport/stmrewrite.py b/pypy/jit/backend/llsupport/stmrewrite.py
--- a/pypy/jit/backend/llsupport/stmrewrite.py
+++ b/pypy/jit/backend/llsupport/stmrewrite.py
@@ -2,6 +2,24 @@
 from pypy.jit.metainterp.resoperation import ResOperation, rop
 from pypy.jit.metainterp.history import BoxPtr, ConstPtr, ConstInt
 
+#
+# STM Support
+# -----------    
+#
+# Any SETFIELD_GC, SETARRAYITEM_GC, SETINTERIORFIELD_GC must be done on a
+# W object.  The operation that forces an object p1 to be W is
+# COND_CALL_GC_WB(p1, 0, descr=x2Wdescr), for x in 'PGORL'.  This
+# COND_CALL_GC_WB is a bit special because if p1 is not W, it *replaces*
+# its value with the W copy (by changing the register's value and
+# patching the stack location if any).  It's still conceptually the same
+# object, but the pointer is different.
+#
+# The case of GETFIELD_GC & friends is similar, excepted that it goes to
+# a R or L object (at first, always a R object).
+#
+# The name "x2y" of write barriers is called the *category* or "cat".
+#
+
 
 class GcStmRewriterAssembler(GcRewriterAssembler):
     # This class performs the same rewrites as its base class,
@@ -76,12 +94,12 @@
         return self.newops
 
 
-    def gen_write_barrier(self, v_base):
+    def gen_write_barrier(self, v_base, cat):
         v_base = self.unconstifyptr(v_base)
         assert isinstance(v_base, BoxPtr)
         if v_base in self.known_local:
             return v_base    # no write barrier needed
-        write_barrier_descr = self.gc_ll_descr.write_barrier_descr
+        write_barrier_descr = getattr(self.gc_ll_descr, '%sdescr' % (cat,))
         args = [v_base, self.c_zero]
         self.newops.append(ResOperation(rop.COND_CALL_GC_WB, args, None,
                                         descr=write_barrier_descr))
@@ -99,7 +117,7 @@
 
     def handle_setfield_operations(self, op):
         lst = op.getarglist()
-        lst[0] = self.gen_write_barrier(lst[0])
+        lst[0] = self.gen_write_barrier(lst[0], 'P2W')
         self.newops.append(op.copy_and_change(op.getopnum(), args=lst))
 
     def handle_malloc_operation(self, op):
diff --git a/pypy/jit/backend/llsupport/test/test_stmrewrite.py b/pypy/jit/backend/llsupport/test/test_stmrewrite.py
--- a/pypy/jit/backend/llsupport/test/test_stmrewrite.py
+++ b/pypy/jit/backend/llsupport/test/test_stmrewrite.py
@@ -29,6 +29,7 @@
                 " descr=stm_try_inevitable_descr)")
         frm_operations = frm_operations.replace('$INEV', inev)
         to_operations  = to_operations .replace('$INEV', inev)
+        namespace['P2Wdescr'] = self.gc_ll_descr.P2Wdescr
         RewriteTests.check_rewrite(self, frm_operations, to_operations,
                                    **namespace)
 
@@ -39,7 +40,7 @@
             jump()
         """, """
             [p1, p2]
-            cond_call_gc_wb(p1, 0, descr=wbdescr)
+            cond_call_gc_wb(p1, 0, descr=P2Wdescr)
             setfield_gc(p1, p2, descr=tzdescr)
             jump()
         """)
diff --git a/pypy/rpython/memory/gc/stmgc.py b/pypy/rpython/memory/gc/stmgc.py
--- a/pypy/rpython/memory/gc/stmgc.py
+++ b/pypy/rpython/memory/gc/stmgc.py
@@ -232,8 +232,6 @@
     def JIT_minimal_size_in_nursery():
         return 0
 
-    JIT_WB_IF_FLAG = GCFLAG_GLOBAL
-
     # ----------
 
     def malloc_fixedsize_clear(self, typeid, size,


More information about the pypy-commit mailing list