Remi Meier avatar Remi Meier committed 21bde47

progress on stm barriers (without fastpath) and GC without malloc fastpaths (nursery)

Comments (0)

Files changed (10)

rpython/jit/backend/llsupport/assembler.py

         self.memcpy_addr = self.cpu.cast_ptr_to_int(memcpy_fn)
         self._build_failure_recovery(False, withfloats=False)
         self._build_failure_recovery(True, withfloats=False)
-        self._build_wb_slowpath(False)
-        self._build_wb_slowpath(True)
-        self._build_wb_slowpath(False, for_frame=True)
+        if gc_ll_descr.stm:
+            descrs = [gc_ll_descr.P2Rdescr, gc_ll_descr.P2Wdescr]
+        else:
+            descrs = [gc_ll_descr.write_barrier_descr]
+        for d in descrs:
+                self._build_b_slowpath(d, False)
+                self._build_b_slowpath(d, True)
+                self._build_b_slowpath(d, False, for_frame=True)
         # only one of those
         self.build_frame_realloc_slowpath()
         if self.cpu.supports_floats:
             self._build_failure_recovery(False, withfloats=True)
             self._build_failure_recovery(True, withfloats=True)
-            self._build_wb_slowpath(False, withfloats=True)
-            self._build_wb_slowpath(True, withfloats=True)
+            for d in descrs:
+                self._build_b_slowpath(d, False, withfloats=True)
+                self._build_b_slowpath(d, True, withfloats=True)
         self._build_propagate_exception_path()
+
         if gc_ll_descr.get_malloc_slowpath_addr() is not None:
             # generate few slowpaths for various cases
             self.malloc_slowpath = self._build_malloc_slowpath(kind='fixed')
             self.malloc_slowpath_varsize = self._build_malloc_slowpath(
                 kind='var')
-        if hasattr(gc_ll_descr, 'malloc_str'):
+        if gc_ll_descr.get_malloc_slowpath_addr() is not None and hasattr(gc_ll_descr, 'malloc_str'):
             self.malloc_slowpath_str = self._build_malloc_slowpath(kind='str')
         else:
             self.malloc_slowpath_str = None
-        if hasattr(gc_ll_descr, 'malloc_unicode'):
+        if gc_ll_descr.get_malloc_slowpath_addr() is not None and hasattr(gc_ll_descr, 'malloc_unicode'):
             self.malloc_slowpath_unicode = self._build_malloc_slowpath(
                 kind='unicode')
         else:

rpython/jit/backend/llsupport/gc.py

         self.returns_modified_object = False
         self.gcheaderbuilder = gc_ll_descr.gcheaderbuilder
         self.HDRPTR = gc_ll_descr.HDRPTR
+        self.b_slowpath = [0, 0, 0, 0]
 
     def repr_of_descr(self):
         raise NotImplementedError
 
     def __repr(self):
         raise NotImplementedError
+
+    def get_b_slowpath(self, num):
+        return self.b_slowpath[num]
+
+    def set_b_slowpath(self, num, addr):
+        self.b_slowpath[num] = addr
+
+    def get_barrier_funcptr(self, returns_modified_object):
+        raise NotImplementedError
+        
+    def get_barrier_fn(self, cpu, returns_modified_object):
+        # must pass in 'self.returns_modified_object', to make sure that
+        # the callers are fixed for this case
+        funcptr = self.get_barrier_funcptr(returns_modified_object)
+        funcaddr = llmemory.cast_ptr_to_adr(funcptr)
+        return cpu.cast_adr_to_int(funcaddr)
+
+    def get_barrier_from_array_fn(self, cpu):
+        # returns a function with arguments [array, index, newvalue]
+        llop1 = self.llop1
+        funcptr = llop1.get_write_barrier_from_array_failing_case(
+            self.FUNCPTR)
+        funcaddr = llmemory.cast_ptr_to_adr(funcptr)
+        return cpu.cast_adr_to_int(funcaddr)    # this may return 0
+
+    def has_barrier_from_array(self, cpu):
+        return self.get_barrier_from_array_fn(cpu) != 0
+
+
         
 class WriteBarrierDescr(BarrierDescr):
     def __init__(self, gc_ll_descr):
             assert self.jit_wb_cards_set_singlebyte == -0x80
         else:
             self.jit_wb_cards_set = 0
-        #
-        self.wb_slowpath = [0, 0, 0, 0]
 
     def repr_of_descr(self):
         return 'wbdescr'
         FUNCTYPE = self.FUNCPTR
         return self.llop1.get_write_barrier_failing_case(FUNCTYPE)
 
-    def get_write_barrier_fn(self, cpu, returns_modified_object):
-        # must pass in 'self.returns_modified_object', to make sure that
-        # the callers are fixed for this case
-        funcptr = self.get_barrier_funcptr(returns_modified_object)
-        funcaddr = llmemory.cast_ptr_to_adr(funcptr)
-        return cpu.cast_adr_to_int(funcaddr)
-
-    def get_write_barrier_from_array_fn(self, cpu):
-        # returns a function with arguments [array, index, newvalue]
-        llop1 = self.llop1
-        funcptr = llop1.get_write_barrier_from_array_failing_case(
-            self.FUNCPTR)
-        funcaddr = llmemory.cast_ptr_to_adr(funcptr)
-        return cpu.cast_adr_to_int(funcaddr)    # this may return 0
-
-    def has_write_barrier_from_array(self, cpu):
-        return self.get_write_barrier_from_array_fn(cpu) != 0
-
-    def get_wb_slowpath(self, withcards, withfloats):
-        return self.wb_slowpath[withcards + 2 * withfloats]
-
-    def set_wb_slowpath(self, withcards, withfloats, addr):
-        self.wb_slowpath[withcards + 2 * withfloats] = addr
-
     @specialize.arg(2)
     def _do_barrier(self, gcref_struct, returns_modified_object):
         assert self.returns_modified_object == returns_modified_object
         
 class STMWriteBarrierDescr(STMBarrierDescr):
     def __init__(self, gc_ll_descr, stmcat):
-        assert stmcat in ['P2W', 'R2W']
+        assert stmcat in ['P2W']
         STMBarrierDescr.__init__(self, gc_ll_descr, stmcat,
                                  'stm_write_barrier')
     
             if not self.stm:
                 # XXX: not needed with stm/shadowstack??
                 self._setup_tid()
+            else:
+                self.fielddescr_tid = None
         self._setup_write_barrier()
         self._setup_str()
         self._make_functions(really_not_translated)
         unicode_itemsize   = self.unicode_descr.itemsize
         unicode_ofs_length = self.unicode_descr.lendescr.offset
 
+        
         def malloc_str(length):
             return llop1.do_malloc_varsize_clear(
                 llmemory.GCREF,
                 str_ofs_length)
         self.generate_function('malloc_str', malloc_str,
                                [lltype.Signed])
-
+            
         def malloc_unicode(length):
             return llop1.do_malloc_varsize_clear(
                 llmemory.GCREF,
     def can_use_nursery_malloc(self, size):
         return (self.max_size_of_young_obj is not None and
                 size < self.max_size_of_young_obj)
-
+        
     def has_write_barrier_class(self):
         return WriteBarrierDescr
 

rpython/jit/backend/llsupport/rewrite.py

         mallocs.  (For all I know this latter case never occurs in
         practice, but better safe than sorry.)
         """
-        if self.gc_ll_descr.fielddescr_tid is not None:  # framework GC
+        if self.gc_ll_descr.fielddescr_tid is not None \
+          or self.gc_ll_descr.stm:  # framework GC
             assert (size & (WORD-1)) == 0, "size not aligned?"
             addr = self.gc_ll_descr.get_malloc_fn_addr('malloc_big_fixedsize')
             args = [ConstInt(addr), ConstInt(size), ConstInt(typeid)]
 
     def gen_write_barrier_array(self, v_base, v_index, v_value):
         write_barrier_descr = self.gc_ll_descr.write_barrier_descr
-        if write_barrier_descr.has_write_barrier_from_array(self.cpu):
+        if write_barrier_descr.has_barrier_from_array(self.cpu):
             # If we know statically the length of 'v', and it is not too
             # big, then produce a regular write_barrier.  If it's unknown or
             # too big, produce instead a write_barrier_from_array.

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

         gcdescr = get_description(config_)
         self.gc_ll_descr = GcLLDescr_framework(gcdescr, None, None, None,
                                                really_not_translated=True)
-        self.gc_ll_descr.write_barrier_descr.has_write_barrier_from_array = (
+        self.gc_ll_descr.write_barrier_descr.has_barrier_from_array = (
             lambda cpu: True)
         #
         class FakeCPU(BaseFakeCPU):
         """)
 
     def test_write_barrier_before_array_without_from_array(self):
-        self.gc_ll_descr.write_barrier_descr.has_write_barrier_from_array = (
+        self.gc_ll_descr.write_barrier_descr.has_barrier_from_array = (
             lambda cpu: False)
         self.check_rewrite("""
             [p1, i2, p3]

rpython/jit/backend/test/runner_test.py

 
 class WBDescrForTests(AbstractDescr):
     returns_modified_object = False
-    wb_slowpath = (0, 0, 0, 0)
-    def get_wb_slowpath(self, c1, c2):
-        return self.wb_slowpath[c1+2*c2]
-    def set_wb_slowpath(self, c1, c2, addr):
+    b_slowpath = (0, 0, 0, 0)
+    def get_b_slowpath(self, c1, c2):
+        return self.b_slowpath[c1+2*c2]
+    def set_b_slowpath(self, c1, c2, addr):
         i = c1+2*c2
-        self.wb_slowpath = (self.wb_slowpath[:i] + (addr,) +
-                            self.wb_slowpath[i+1:])
+        self.b_slowpath = (self.b_slowpath[:i] + (addr,) +
+                            self.b_slowpath[i+1:])
         

rpython/jit/backend/x86/assembler.py

         self.float_const_abs_addr = 0
         self.malloc_slowpath = 0
         self.malloc_slowpath_varsize = 0
-        self.wb_slowpath = [0, 0, 0, 0, 0]
         self.setup_failure_recovery()
         self.datablockwrapper = None
         self.stack_check_slowpath = 0
         rawstart = mc.materialize(self.cpu.asmmemmgr, [])
         self.stack_check_slowpath = rawstart
 
-    def _build_wb_slowpath(self, withcards, withfloats=False, for_frame=False):
-        descr = self.cpu.gc_ll_descr.write_barrier_descr
+    def _build_b_slowpath(self, descr, withcards, withfloats=False,
+                          for_frame=False):
+        is_stm = self.cpu.gc_ll_descr.stm
         exc0, exc1 = None, None
         if descr is None:
             return
+        
         if not withcards:
-            func = descr.get_write_barrier_fn(self.cpu)
+            func = descr.get_barrier_fn(self.cpu, 
+                                        returns_modified_object=is_stm)
         else:
+            assert not is_stm
             if descr.jit_wb_cards_set == 0:
                 return
-            func = descr.get_write_barrier_from_array_fn(self.cpu)
+            func = descr.get_barrier_from_array_fn(self.cpu)
             if func == 0:
                 return
         #
             self._store_and_reset_exception(mc, exc0, exc1)
 
         mc.CALL(imm(func))
-        #
+
+        if descr.returns_modified_object:
+            # new addr in eax, save in scratch reg
+            mc.PUSH_r(eax.value)
+                
         if withcards:
             # A final TEST8 before the RET, for the caller.  Careful to
             # not follow this instruction with another one that changes
             # the status of the CPU flags!
+            assert not is_stm
             if IS_X86_32:
                 mc.MOV_rs(eax.value, 3*WORD)
             else:
             mc.TEST8(addr_add_const(eax, descr.jit_wb_if_flag_byteofs),
                      imm(-0x80))
         #
-
         if not for_frame:
             if IS_X86_32:
                 # ADD touches CPU flags
                 mc.LEA_rs(esp.value, 2 * WORD)
             self._pop_all_regs_from_frame(mc, [], withfloats, callee_only=True)
+
+            if descr.returns_modified_object:
+                mc.POP_r(eax.value)
             mc.RET16_i(WORD)
         else:
             if IS_X86_32:
             mc.MOV(exc0, RawEspLoc(WORD * 5, REF))
             mc.MOV(exc1, RawEspLoc(WORD * 6, INT))
             mc.LEA_rs(esp.value, 7 * WORD)
+
+            if descr.returns_modified_object:
+                mc.POP_r(eax.value)
             mc.RET()
 
         rawstart = mc.materialize(self.cpu.asmmemmgr, [])
         if for_frame:
-            self.wb_slowpath[4] = rawstart
+            descr.set_b_slowpath(4, rawstart)
         else:
-            self.wb_slowpath[withcards + 2 * withfloats] = rawstart
+            descr.set_b_slowpath(withcards + 2 * withfloats, rawstart)
 
     def assemble_loop(self, loopname, inputargs, operations, looptoken, log):
         '''adds the following attributes to looptoken:
 
         if gcrootmap and gcrootmap.is_stm:
             wbdescr = self.cpu.gc_ll_descr.P2Wdescr
-        else:
-            wbdescr = self.cpu.gc_ll_descr.write_barrier_descr
-            
+            self._stm_barrier_fastpath(mc, wbdescr, [ebp], is_frame=True,
+                                       align_stack=align_stack)
+            return
+
+        wbdescr = self.cpu.gc_ll_descr.write_barrier_descr
         if gcrootmap and wbdescr:
             # frame never uses card marking, so we enforce this is not
             # an array
         self.mc.overwrite(jmp_location - 1, chr(offset))
 
     # ------------------- END CALL ASSEMBLER -----------------------
+    def _stm_barrier_fastpath(self, mc, descr, arglocs, is_frame=False,
+                              align_stack=False):
+        assert self.cpu.gc_ll_descr.stm
+        from rpython.jit.backend.llsupport.gc import STMBarrierDescr
+        assert isinstance(descr, STMBarrierDescr)
+        assert descr.returns_modified_object        
+        loc_base = arglocs[0]
+        assert isinstance(loc_base, RegLoc)
+        # Write only a CALL to the helper prepared in advance, passing it as
+        # argument the address of the structure we are writing into
+        # (the first argument to COND_CALL_GC_WB).
+        helper_num = 0
+        if is_frame:
+            helper_num = 4
+        elif self._regalloc is not None and self._regalloc.xrm.reg_bindings:
+            helper_num += 2
+        #
+        if not is_frame:
+            mc.PUSH(loc_base)
+        if is_frame and align_stack:
+            mc.SUB_ri(esp.value, 16 - WORD) # erase the return address
+        func = descr.get_b_slowpath(helper_num)
+        mc.CALL(imm(func))
+        mc.MOV_rr(loc_base.value, eax.value)
+        if is_frame and align_stack:
+            mc.ADD_ri(esp.value, 16 - WORD) # erase the return address
 
+
+
+        
     def _write_barrier_fastpath(self, mc, descr, arglocs, array=False,
                                 is_frame=False, align_stack=False):
         # Write code equivalent to write_barrier() in the GC: it checks
         # a flag in the object at arglocs[0], and if set, it calls a
         # helper piece of assembler.  The latter saves registers as needed
         # and call the function jit_remember_young_pointer() from the GC.
+        assert not self.cpu.gc_ll_descr.stm
         if we_are_translated():
             cls = self.cpu.gc_ll_descr.has_write_barrier_class()
             assert cls is not None and isinstance(descr, cls)
             helper_num = 4
         elif self._regalloc is not None and self._regalloc.xrm.reg_bindings:
             helper_num += 2
-        if self.wb_slowpath[helper_num] == 0:    # tests only
+        if descr.get_b_slowpath(helper_num) == 0:    # tests only
             assert not we_are_translated()
             self.cpu.gc_ll_descr.write_barrier_descr = descr
-            self._build_wb_slowpath(card_marking,
-                                    bool(self._regalloc.xrm.reg_bindings))
-            assert self.wb_slowpath[helper_num] != 0
+            self._build_b_slowpath(descr, card_marking,
+                                   bool(self._regalloc.xrm.reg_bindings))
+            assert descr.get_b_slowpath(helper_num) != 0
         #
         if not is_frame:
             mc.PUSH(loc_base)
         if is_frame and align_stack:
             mc.SUB_ri(esp.value, 16 - WORD) # erase the return address
-        mc.CALL(imm(self.wb_slowpath[helper_num]))
+        mc.CALL(imm(descr.get_b_slowpath(helper_num)))
         if is_frame and align_stack:
             mc.ADD_ri(esp.value, 16 - WORD) # erase the return address
 
         self._write_barrier_fastpath(self.mc, op.getdescr(), arglocs,
                                      array=True)
 
+    def genop_discard_cond_call_stm_b(self, op, arglocs):
+        self._stm_barrier_fastpath(self.mc, op.getdescr(), arglocs)
+
     def not_implemented_op_discard(self, op, arglocs):
         not_implemented("not implemented operation: %s" % op.getopname())
 
         self._check_frame_depth_debug(self.mc)
 
     def malloc_cond(self, nursery_free_adr, nursery_top_adr, size, gcmap):
+        assert not self.cpu.gc_ll_descr.stm
         assert size & (WORD-1) == 0     # must be correctly aligned
         self.mc.MOV(eax, heap(nursery_free_adr))
         self.mc.LEA_rm(edi.value, (eax.value, size))
 
     def malloc_cond_varsize_frame(self, nursery_free_adr, nursery_top_adr,
                                   sizeloc, gcmap):
+        assert not self.cpu.gc_ll_descr.stm
         if sizeloc is eax:
             self.mc.MOV(edi, sizeloc)
             sizeloc = edi
     def malloc_cond_varsize(self, kind, nursery_free_adr, nursery_top_adr,
                             lengthloc, itemsize, maxlength, gcmap,
                             arraydescr):
+        assert not self.cpu.gc_ll_descr.stm
         from rpython.jit.backend.llsupport.descr import ArrayDescr
         assert isinstance(arraydescr, ArrayDescr)
 

rpython/jit/backend/x86/regalloc.py

         self.perform_discard(op, arglocs)
 
     consider_cond_call_gc_wb_array = consider_cond_call_gc_wb
+    consider_cond_call_stm_b       = consider_cond_call_gc_wb
 
     def consider_call_malloc_nursery(self, op):
         gc_ll_descr = self.assembler.cpu.gc_ll_descr
             size, gcmap)
 
     def consider_call_malloc_nursery_varsize_frame(self, op):
+        gc_ll_descr = self.assembler.cpu.gc_ll_descr
+        assert gc_ll_descr.max_size_of_young_obj is not None
+        # ^^^ if this returns None, don't translate the rest of this function
+        #
         size_box = op.getarg(0)
         assert isinstance(size_box, BoxInt) # we cannot have a const here!
         # sizeloc must be in a register, but we can free it now
 
     def consider_call_malloc_nursery_varsize(self, op):
         gc_ll_descr = self.assembler.cpu.gc_ll_descr
+        assert gc_ll_descr.max_size_of_young_obj is not None
+        # ^^^ if this returns None, don't translate the rest of this function
+        #
         if not hasattr(gc_ll_descr, 'max_size_of_young_obj'):
             raise Exception("unreachable code")
             # for boehm, this function should never be called

rpython/memory/gc/stmgc.py

 
     @classmethod
     def JIT_max_size_of_young_obj(cls):
-        return -1 # XXX: should not be used
+        return None
 
     @classmethod
     def JIT_minimal_size_in_nursery(cls):

rpython/memory/gctransform/framework.py

                 # 'no_collect' function can trigger collection
                 import cStringIO
                 err = cStringIO.StringIO()
+                import sys
                 prev = sys.stdout
                 try:
                     sys.stdout = err

rpython/memory/gctransform/stmframework.py

         return self.gcdata.gc.gcheaderbuilder.header_of_object(obj)
 
     def gct_gc_adr_of_root_stack_top(self, hop):
-        hop.genop("stm_get_root_stack_top")
+        hop.genop("stm_get_root_stack_top", [], resultvar=hop.spaceop.result)
 
     def _gct_with_roots_pushed(self, hop):
         livevars = self.push_roots(hop)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.