[pypy-svn] r71885 - in pypy/branch/jit-constptr/pypy: jit/backend/llsupport jit/backend/llsupport/test jit/backend/x86 jit/backend/x86/test rpython/memory/gc rpython/memory/gctransform

arigo at codespeak.net arigo at codespeak.net
Mon Mar 8 16:22:16 CET 2010


Author: arigo
Date: Mon Mar  8 16:22:14 2010
New Revision: 71885

Added:
   pypy/branch/jit-constptr/pypy/jit/backend/llsupport/gcframework.py
      - copied, changed from r71876, pypy/branch/jit-constptr/pypy/jit/backend/llsupport/gc.py
Modified:
   pypy/branch/jit-constptr/pypy/jit/backend/llsupport/gc.py
   pypy/branch/jit-constptr/pypy/jit/backend/llsupport/test/test_gc.py
   pypy/branch/jit-constptr/pypy/jit/backend/x86/runner.py
   pypy/branch/jit-constptr/pypy/jit/backend/x86/test/test_zrpy_gc.py
   pypy/branch/jit-constptr/pypy/rpython/memory/gc/base.py
   pypy/branch/jit-constptr/pypy/rpython/memory/gctransform/framework.py
Log:
In-progress.  Adds a hook in the GC, called before and after tracing of
some kinds of objects (more precisely, the arrays with GcRefs in the
varsized part, and which are not just GcArrays).

Start using the hook from the JIT.  See test_GcRefHandler.
The goal is to correct the addresses of objects, or of individual
fields inside these objects, that are hard-coded in assembler.



Modified: pypy/branch/jit-constptr/pypy/jit/backend/llsupport/gc.py
==============================================================================
--- pypy/branch/jit-constptr/pypy/jit/backend/llsupport/gc.py	(original)
+++ pypy/branch/jit-constptr/pypy/jit/backend/llsupport/gc.py	Mon Mar  8 16:22:14 2010
@@ -1,20 +1,8 @@
-from pypy.rlib import rgc
-from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.debug import fatalerror
-from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass, rstr
-from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.rpython.annlowlevel import llhelper
-from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.jit.metainterp.history import BoxInt, BoxPtr, ConstInt, ConstPtr
-from pypy.jit.metainterp.history import AbstractDescr
-from pypy.jit.metainterp.resoperation import ResOperation, rop
+from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr
 from pypy.jit.backend.llsupport import symbolic
 from pypy.jit.backend.llsupport.symbolic import WORD
 from pypy.jit.backend.llsupport.descr import BaseSizeDescr, BaseArrayDescr
-from pypy.jit.backend.llsupport.descr import GcCache, get_field_descr
-from pypy.jit.backend.llsupport.descr import GcPtrFieldDescr
-from pypy.jit.backend.llsupport.descr import get_call_descr
-from pypy.rlib.rarithmetic import r_ulonglong, r_uint
+from pypy.jit.backend.llsupport.descr import GcCache
 
 # ____________________________________________________________
 
@@ -121,480 +109,11 @@
     get_funcptr_for_newstr = None
     get_funcptr_for_newunicode = None
 
-
 # ____________________________________________________________
-# All code below is for the hybrid GC
-
-
-class GcRefList:
-    """Handles all references from the generated assembler to GC objects.
-    This is implemented as a nonmovable, but GC, list; the assembler contains
-    code that will (for now) always read from this list."""
-
-    GCREF_LIST = lltype.GcArray(llmemory.GCREF)     # followed by the GC
-
-    HASHTABLE = rffi.CArray(llmemory.Address)      # ignored by the GC
-    HASHTABLE_BITS = 10
-    HASHTABLE_SIZE = 1 << HASHTABLE_BITS
-
-    def initialize(self):
-        if we_are_translated(): n = 2000
-        else:                   n = 10    # tests only
-        self.list = self.alloc_gcref_list(n)
-        self.nextindex = 0
-        self.oldlists = []
-        # A pseudo dictionary: it is fixed size, and it may contain
-        # random nonsense after a collection moved the objects.  It is only
-        # used to avoid too many duplications in the GCREF_LISTs.
-        self.hashtable = lltype.malloc(self.HASHTABLE,
-                                       self.HASHTABLE_SIZE+1,
-                                       flavor='raw')
-        dummy = lltype.direct_ptradd(lltype.direct_arrayitems(self.hashtable),
-                                     self.HASHTABLE_SIZE)
-        dummy = llmemory.cast_ptr_to_adr(dummy)
-        for i in range(self.HASHTABLE_SIZE+1):
-            self.hashtable[i] = dummy
-
-    def alloc_gcref_list(self, n):
-        # Important: the GRREF_LISTs allocated are *non-movable*.  This
-        # requires support in the gc (only the hybrid GC supports it so far).
-        if we_are_translated():
-            list = rgc.malloc_nonmovable(self.GCREF_LIST, n)
-            assert list, "malloc_nonmovable failed!"
-        else:
-            list = lltype.malloc(self.GCREF_LIST, n)     # for tests only
-        return list
-
-    def get_address_of_gcref(self, gcref):
-        assert lltype.typeOf(gcref) == llmemory.GCREF
-        # first look in the hashtable, using an inexact hash (fails after
-        # the object moves)
-        addr = llmemory.cast_ptr_to_adr(gcref)
-        hash = llmemory.cast_adr_to_int(addr)
-        hash -= hash >> self.HASHTABLE_BITS
-        hash &= self.HASHTABLE_SIZE - 1
-        addr_ref = self.hashtable[hash]
-        # the following test is safe anyway, because the addresses found
-        # in the hashtable are always the addresses of nonmovable stuff
-        # ('addr_ref' is an address inside self.list, not directly the
-        # address of a real moving GC object -- that's 'addr_ref.address[0]'.)
-        if addr_ref.address[0] == addr:
-            return addr_ref
-        # if it fails, add an entry to the list
-        if self.nextindex == len(self.list):
-            # reallocate first, increasing a bit the size every time
-            self.oldlists.append(self.list)
-            self.list = self.alloc_gcref_list(len(self.list) // 4 * 5)
-            self.nextindex = 0
-        # add it
-        index = self.nextindex
-        self.list[index] = gcref
-        addr_ref = lltype.direct_ptradd(lltype.direct_arrayitems(self.list),
-                                        index)
-        addr_ref = llmemory.cast_ptr_to_adr(addr_ref)
-        self.nextindex = index + 1
-        # record it in the hashtable
-        self.hashtable[hash] = addr_ref
-        return addr_ref
-
-
-class GcRootMap_asmgcc:
-    """Handles locating the stack roots in the assembler.
-    This is the class supporting --gcrootfinder=asmgcc.
-    """
-    LOC_REG       = 0
-    LOC_ESP_PLUS  = 1
-    LOC_EBP_PLUS  = 2
-    LOC_EBP_MINUS = 3
-
-    GCMAP_ARRAY = rffi.CArray(llmemory.Address)
-    CALLSHAPE_ARRAY = rffi.CArray(rffi.UCHAR)
-
-    def __init__(self):
-        self._gcmap = lltype.nullptr(self.GCMAP_ARRAY)
-        self._gcmap_curlength = 0
-        self._gcmap_maxlength = 0
-
-    def initialize(self):
-        # hack hack hack.  Remove these lines and see MissingRTypeAttribute
-        # when the rtyper tries to annotate these methods only when GC-ing...
-        self.gcmapstart()
-        self.gcmapend()
-
-    def gcmapstart(self):
-        return llmemory.cast_ptr_to_adr(self._gcmap)
-
-    def gcmapend(self):
-        addr = self.gcmapstart()
-        if self._gcmap_curlength:
-            addr += llmemory.sizeof(llmemory.Address)*self._gcmap_curlength
-        return addr
-
-    def put(self, retaddr, callshapeaddr):
-        """'retaddr' is the address just after the CALL.
-        'callshapeaddr' is the address returned by encode_callshape()."""
-        index = self._gcmap_curlength
-        if index + 2 > self._gcmap_maxlength:
-            self._enlarge_gcmap()
-        self._gcmap[index] = retaddr
-        self._gcmap[index+1] = callshapeaddr
-        self._gcmap_curlength = index + 2
-
-    def _enlarge_gcmap(self):
-        newlength = 250 + self._gcmap_maxlength * 2
-        newgcmap = lltype.malloc(self.GCMAP_ARRAY, newlength, flavor='raw')
-        oldgcmap = self._gcmap
-        for i in range(self._gcmap_curlength):
-            newgcmap[i] = oldgcmap[i]
-        self._gcmap = newgcmap
-        self._gcmap_maxlength = newlength
-        if oldgcmap:
-            lltype.free(oldgcmap, flavor='raw')
-
-    def get_basic_shape(self):
-        return [chr(self.LOC_EBP_PLUS  | 4),    # return addr: at   4(%ebp)
-                chr(self.LOC_EBP_MINUS | 4),    # saved %ebx:  at  -4(%ebp)
-                chr(self.LOC_EBP_MINUS | 8),    # saved %esi:  at  -8(%ebp)
-                chr(self.LOC_EBP_MINUS | 12),   # saved %edi:  at -12(%ebp)
-                chr(self.LOC_EBP_PLUS  | 0),    # saved %ebp:  at    (%ebp)
-                chr(0)]
-
-    def _encode_num(self, shape, number):
-        assert number >= 0
-        flag = 0
-        while number >= 0x80:
-            shape.append(chr((number & 0x7F) | flag))
-            flag = 0x80
-            number >>= 7
-        shape.append(chr(number | flag))
-
-    def add_ebp_offset(self, shape, offset):
-        assert (offset & 3) == 0
-        if offset >= 0:
-            num = self.LOC_EBP_PLUS | offset
-        else:
-            num = self.LOC_EBP_MINUS | (-offset)
-        self._encode_num(shape, num)
-
-    def add_ebx(self, shape):
-        shape.append(chr(self.LOC_REG | 4))
 
-    def add_esi(self, shape):
-        shape.append(chr(self.LOC_REG | 8))
-
-    def add_edi(self, shape):
-        shape.append(chr(self.LOC_REG | 12))
-
-    def add_ebp(self, shape):
-        shape.append(chr(self.LOC_REG | 16))
-
-    def compress_callshape(self, shape):
-        # Similar to compress_callshape() in trackgcroot.py.
-        # XXX so far, we always allocate a new small array (we could regroup
-        # them inside bigger arrays) and we never try to share them.
-        length = len(shape)
-        compressed = lltype.malloc(self.CALLSHAPE_ARRAY, length,
-                                   flavor='raw')
-        for i in range(length):
-            compressed[length-1-i] = rffi.cast(rffi.UCHAR, shape[i])
-        return llmemory.cast_ptr_to_adr(compressed)
-
-
-class WriteBarrierDescr(AbstractDescr):
-    def __init__(self, gc_ll_descr):
-        self.llop1 = gc_ll_descr.llop1
-        self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR
-        self.fielddescr_tid = get_field_descr(gc_ll_descr,
-                                              gc_ll_descr.GCClass.HDR, 'tid')
-        self.jit_wb_if_flag = gc_ll_descr.GCClass.JIT_WB_IF_FLAG
-        # if convenient for the backend, we also compute the info about
-        # the flag as (byte-offset, single-byte-flag).
-        import struct
-        value = struct.pack("i", self.jit_wb_if_flag)
-        assert value.count('\x00') == len(value) - 1    # only one byte is != 0
-        i = 0
-        while value[i] == '\x00': i += 1
-        self.jit_wb_if_flag_byteofs = i
-        self.jit_wb_if_flag_singlebyte = struct.unpack('b', value[i])[0]
-
-    def get_write_barrier_fn(self, cpu):
-        llop1 = self.llop1
-        funcptr = llop1.get_write_barrier_failing_case(self.WB_FUNCPTR)
-        funcaddr = llmemory.cast_ptr_to_adr(funcptr)
-        return cpu.cast_adr_to_int(funcaddr)
-
-
-class GcLLDescr_framework(GcLLDescription):
-
-    def __init__(self, gcdescr, translator, llop1=llop):
-        from pypy.rpython.memory.gctypelayout import _check_typeid
-        from pypy.rpython.memory.gcheader import GCHeaderBuilder
-        from pypy.rpython.memory.gctransform import framework
-        GcLLDescription.__init__(self, gcdescr, translator)
-        assert self.translate_support_code, "required with the framework GC"
-        self.translator = translator
-        self.llop1 = llop1
-
-        # we need the hybrid GC for GcRefList.alloc_gcref_list() to work
-        if gcdescr.config.translation.gc != 'hybrid':
-            raise NotImplementedError("--gc=%s not implemented with the JIT" %
-                                      (gcdescr.config.translation.gc,))
-
-        # to find roots in the assembler, make a GcRootMap
-        name = gcdescr.config.translation.gcrootfinder
-        try:
-            cls = globals()['GcRootMap_' + name]
-        except KeyError:
-            raise NotImplementedError("--gcrootfinder=%s not implemented"
-                                      " with the JIT" % (name,))
-        gcrootmap = cls()
-        self.gcrootmap = gcrootmap
-        self.gcrefs = GcRefList()
-        self.single_gcref_descr = GcPtrFieldDescr(0)
-
-        # make a TransformerLayoutBuilder and save it on the translator
-        # where it can be fished and reused by the FrameworkGCTransformer
-        self.layoutbuilder = framework.TransformerLayoutBuilder(translator)
-        self.layoutbuilder.delay_encoding()
-        self.translator._jit2gc = {
-            'layoutbuilder': self.layoutbuilder,
-            'gcmapstart': lambda: gcrootmap.gcmapstart(),
-            'gcmapend': lambda: gcrootmap.gcmapend(),
-            }
-        self.GCClass = self.layoutbuilder.GCClass
-        self.moving_gc = self.GCClass.moving_gc
-        self.HDRPTR = lltype.Ptr(self.GCClass.HDR)
-        self.gcheaderbuilder = GCHeaderBuilder(self.HDRPTR.TO)
-        (self.array_basesize, _, self.array_length_ofs) = \
-             symbolic.get_array_token(lltype.GcArray(lltype.Signed), True)
-        min_ns = self.GCClass.TRANSLATION_PARAMS['min_nursery_size']
-        self.max_size_of_young_obj = self.GCClass.get_young_fixedsize(min_ns)
-
-        # make a malloc function, with three arguments
-        def malloc_basic(size, tid):
-            type_id = llop.extract_ushort(rffi.USHORT, tid)
-            has_finalizer = bool(tid & (1<<16))
-            _check_typeid(type_id)
-            try:
-                res = llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
-                                                      type_id, size, True,
-                                                      has_finalizer, False)
-            except MemoryError:
-                fatalerror("out of memory (from JITted code)")
-                res = lltype.nullptr(llmemory.GCREF.TO)
-            #llop.debug_print(lltype.Void, "\tmalloc_basic", size, type_id,
-            #                 "-->", res)
-            return res
-        self.malloc_basic = malloc_basic
-        self.GC_MALLOC_BASIC = lltype.Ptr(lltype.FuncType(
-            [lltype.Signed, lltype.Signed], llmemory.GCREF))
-        self.WB_FUNCPTR = lltype.Ptr(lltype.FuncType(
-            [llmemory.Address, llmemory.Address], lltype.Void))
-        self.write_barrier_descr = WriteBarrierDescr(self)
-        #
-        def malloc_array(itemsize, tid, num_elem):
-            type_id = llop.extract_ushort(rffi.USHORT, tid)
-            _check_typeid(type_id)
-            try:
-                return llop1.do_malloc_varsize_clear(
-                    llmemory.GCREF,
-                    type_id, num_elem, self.array_basesize, itemsize,
-                    self.array_length_ofs, True)
-            except MemoryError:
-                fatalerror("out of memory (from JITted code)")
-                return lltype.nullptr(llmemory.GCREF.TO)
-        self.malloc_array = malloc_array
-        self.GC_MALLOC_ARRAY = lltype.Ptr(lltype.FuncType(
-            [lltype.Signed] * 3, llmemory.GCREF))
-        #
-        (str_basesize, str_itemsize, str_ofs_length
-         ) = symbolic.get_array_token(rstr.STR, True)
-        (unicode_basesize, unicode_itemsize, unicode_ofs_length
-         ) = symbolic.get_array_token(rstr.UNICODE, True)
-        str_type_id = self.layoutbuilder.get_type_id(rstr.STR)
-        unicode_type_id = self.layoutbuilder.get_type_id(rstr.UNICODE)
-        #
-        def malloc_str(length):
-            try:
-                return llop1.do_malloc_varsize_clear(
-                    llmemory.GCREF,
-                    str_type_id, length, str_basesize, str_itemsize,
-                    str_ofs_length, True)
-            except MemoryError:
-                fatalerror("out of memory (from JITted code)")
-                return lltype.nullptr(llmemory.GCREF.TO)
-        def malloc_unicode(length):
-            try:
-                return llop1.do_malloc_varsize_clear(
-                    llmemory.GCREF,
-                    unicode_type_id, length, unicode_basesize,unicode_itemsize,
-                    unicode_ofs_length, True)
-            except MemoryError:
-                fatalerror("out of memory (from JITted code)")
-                return lltype.nullptr(llmemory.GCREF.TO)
-        self.malloc_str = malloc_str
-        self.malloc_unicode = malloc_unicode
-        self.GC_MALLOC_STR_UNICODE = lltype.Ptr(lltype.FuncType(
-            [lltype.Signed], llmemory.GCREF))
-        def malloc_fixedsize_slowpath(size):
-            try:
-                gcref = llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
-                                            0, size, True, False, False)
-            except MemoryError:
-                fatalerror("out of memory (from JITted code)")
-                return r_ulonglong(0)
-            res = rffi.cast(lltype.Signed, gcref)
-            nurs_free = llop1.gc_adr_of_nursery_free(llmemory.Address).signed[0]
-            return r_ulonglong(nurs_free) << 32 | r_ulonglong(r_uint(res))
-        self.malloc_fixedsize_slowpath = malloc_fixedsize_slowpath
-        self.MALLOC_FIXEDSIZE_SLOWPATH = lltype.FuncType([lltype.Signed],
-                                                 lltype.UnsignedLongLong)
-
-    def get_nursery_free_addr(self):
-        nurs_addr = llop.gc_adr_of_nursery_free(llmemory.Address)
-        return rffi.cast(lltype.Signed, nurs_addr)
-
-    def get_nursery_top_addr(self):
-        nurs_top_addr = llop.gc_adr_of_nursery_top(llmemory.Address)
-        return rffi.cast(lltype.Signed, nurs_top_addr)
-
-    def get_malloc_fixedsize_slowpath_addr(self):
-        fptr = llhelper(lltype.Ptr(self.MALLOC_FIXEDSIZE_SLOWPATH),
-                        self.malloc_fixedsize_slowpath)
-        return rffi.cast(lltype.Signed, fptr)
-
-    def initialize(self):
-        self.gcrefs.initialize()
-        self.gcrootmap.initialize()
-
-    def init_size_descr(self, S, descr):
-        type_id = self.layoutbuilder.get_type_id(S)
-        assert not self.layoutbuilder.is_weakref(type_id)
-        has_finalizer = bool(self.layoutbuilder.has_finalizer(S))
-        flags = int(has_finalizer) << 16
-        descr.tid = llop.combine_ushort(lltype.Signed, type_id, flags)
-
-    def init_array_descr(self, A, descr):
-        type_id = self.layoutbuilder.get_type_id(A)
-        descr.tid = llop.combine_ushort(lltype.Signed, type_id, 0)
-
-    def gc_malloc(self, sizedescr):
-        assert isinstance(sizedescr, BaseSizeDescr)
-        return self.malloc_basic(sizedescr.size, sizedescr.tid)
-
-    def gc_malloc_array(self, arraydescr, num_elem):
-        assert isinstance(arraydescr, BaseArrayDescr)
-        itemsize = arraydescr.get_item_size(self.translate_support_code)
-        return self.malloc_array(itemsize, arraydescr.tid, num_elem)
-
-    def gc_malloc_str(self, num_elem):
-        return self.malloc_str(num_elem)
-
-    def gc_malloc_unicode(self, num_elem):
-        return self.malloc_unicode(num_elem)
-
-    def args_for_new(self, sizedescr):
-        assert isinstance(sizedescr, BaseSizeDescr)
-        return [sizedescr.size, sizedescr.tid]
-
-    def args_for_new_array(self, arraydescr):
-        assert isinstance(arraydescr, BaseArrayDescr)
-        itemsize = arraydescr.get_item_size(self.translate_support_code)
-        return [itemsize, arraydescr.tid]
-
-    def get_funcptr_for_new(self):
-        return llhelper(self.GC_MALLOC_BASIC, self.malloc_basic)
-
-    def get_funcptr_for_newarray(self):
-        return llhelper(self.GC_MALLOC_ARRAY, self.malloc_array)
-
-    def get_funcptr_for_newstr(self):
-        return llhelper(self.GC_MALLOC_STR_UNICODE, self.malloc_str)
-
-    def get_funcptr_for_newunicode(self):
-        return llhelper(self.GC_MALLOC_STR_UNICODE, self.malloc_unicode)
-
-    def do_write_barrier(self, gcref_struct, gcref_newptr):
-        hdr_addr = llmemory.cast_ptr_to_adr(gcref_struct)
-        hdr_addr -= self.gcheaderbuilder.size_gc_header
-        hdr = llmemory.cast_adr_to_ptr(hdr_addr, self.HDRPTR)
-        if hdr.tid & self.GCClass.JIT_WB_IF_FLAG:
-            # get a pointer to the 'remember_young_pointer' function from
-            # the GC, and call it immediately
-            llop1 = self.llop1
-            funcptr = llop1.get_write_barrier_failing_case(self.WB_FUNCPTR)
-            funcptr(llmemory.cast_ptr_to_adr(gcref_struct),
-                    llmemory.cast_ptr_to_adr(gcref_newptr))
-
-    def rewrite_assembler(self, cpu, operations):
-        # Perform two kinds of rewrites in parallel:
-        #
-        # - Add COND_CALLs to the write barrier before SETFIELD_GC and
-        #   SETARRAYITEM_GC operations.
-        #
-        # - Remove all uses of ConstPtrs away from the assembler.
-        #   Idea: when running on a moving GC, we can't (easily) encode
-        #   the ConstPtrs in the assembler, because they can move at any
-        #   point in time.  Instead, we store them in 'gcrefs.list', a GC
-        #   but nonmovable list; and here, we modify 'operations' to
-        #   replace direct usage of ConstPtr with a BoxPtr loaded by a
-        #   GETFIELD_RAW from the array 'gcrefs.list'.
-        #
-        newops = []
-        for op in operations:
-            if op.opnum == rop.DEBUG_MERGE_POINT:
-                continue
-            # ---------- replace ConstPtrs with GETFIELD_RAW ----------
-            # xxx some performance issue here
-            for i in range(len(op.args)):
-                v = op.args[i]
-                if isinstance(v, ConstPtr) and bool(v.value):
-                    addr = self.gcrefs.get_address_of_gcref(v.value)
-                    # ^^^even for non-movable objects, to record their presence
-                    if rgc.can_move(v.value):
-                        box = BoxPtr(v.value)
-                        addr = cpu.cast_adr_to_int(addr)
-                        newops.append(ResOperation(rop.GETFIELD_RAW,
-                                                   [ConstInt(addr)], box,
-                                                   self.single_gcref_descr))
-                        op.args[i] = box
-            # ---------- write barrier for SETFIELD_GC ----------
-            if op.opnum == rop.SETFIELD_GC:
-                v = op.args[1]
-                if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
-                                             bool(v.value)): # store a non-NULL
-                    self._gen_write_barrier(newops, op.args[0], v)
-                    op = ResOperation(rop.SETFIELD_RAW, op.args, None,
-                                      descr=op.descr)
-            # ---------- write barrier for SETARRAYITEM_GC ----------
-            if op.opnum == rop.SETARRAYITEM_GC:
-                v = op.args[2]
-                if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
-                                             bool(v.value)): # store a non-NULL
-                    self._gen_write_barrier(newops, op.args[0], v)
-                    op = ResOperation(rop.SETARRAYITEM_RAW, op.args, None,
-                                      descr=op.descr)
-            # ----------
-            newops.append(op)
-        del operations[:]
-        operations.extend(newops)
-
-    def _gen_write_barrier(self, newops, v_base, v_value):
-        args = [v_base, v_value]
-        newops.append(ResOperation(rop.COND_CALL_GC_WB, args, None,
-                                   descr=self.write_barrier_descr))
-
-    def can_inline_malloc(self, descr):
-        assert isinstance(descr, BaseSizeDescr)
-        if descr.size < self.max_size_of_young_obj:
-            has_finalizer = bool(descr.tid & (1<<16))
-            if has_finalizer:
-                return False
-            return True
-        return False
-
-    def has_write_barrier_class(self):
-        return WriteBarrierDescr
+def GcLLDescr_framework(*args):
+    from pypy.jit.backend.llsupport import gcframework
+    return gcframework.GcLLDescr_framework(*args)
 
 # ____________________________________________________________
 

Copied: pypy/branch/jit-constptr/pypy/jit/backend/llsupport/gcframework.py (from r71876, pypy/branch/jit-constptr/pypy/jit/backend/llsupport/gc.py)
==============================================================================
--- pypy/branch/jit-constptr/pypy/jit/backend/llsupport/gc.py	(original)
+++ pypy/branch/jit-constptr/pypy/jit/backend/llsupport/gcframework.py	Mon Mar  8 16:22:14 2010
@@ -1,201 +1,82 @@
-from pypy.rlib import rgc
-from pypy.rlib.objectmodel import we_are_translated
+from pypy.jit.backend.llsupport.gc import GcLLDescription
 from pypy.rlib.debug import fatalerror
-from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass, rstr
+from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.annlowlevel import llhelper
-from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.jit.metainterp.history import BoxInt, BoxPtr, ConstInt, ConstPtr
+from pypy.jit.metainterp.history import BoxPtr, ConstPtr
 from pypy.jit.metainterp.history import AbstractDescr
 from pypy.jit.metainterp.resoperation import ResOperation, rop
 from pypy.jit.backend.llsupport import symbolic
-from pypy.jit.backend.llsupport.symbolic import WORD
 from pypy.jit.backend.llsupport.descr import BaseSizeDescr, BaseArrayDescr
-from pypy.jit.backend.llsupport.descr import GcCache, get_field_descr
+from pypy.jit.backend.llsupport.descr import get_field_descr
 from pypy.jit.backend.llsupport.descr import GcPtrFieldDescr
 from pypy.jit.backend.llsupport.descr import get_call_descr
 from pypy.rlib.rarithmetic import r_ulonglong, r_uint
 
-# ____________________________________________________________
-
-class GcLLDescription(GcCache):
-    def __init__(self, gcdescr, translator=None):
-        GcCache.__init__(self, translator is not None)
-        self.gcdescr = gcdescr
-    def _freeze_(self):
-        return True
-    def initialize(self):
-        pass
-    def do_write_barrier(self, gcref_struct, gcref_newptr):
-        pass
-    def rewrite_assembler(self, cpu, operations):
-        pass
-    def can_inline_malloc(self, descr):
-        return False
-    def has_write_barrier_class(self):
-        return None
-
-# ____________________________________________________________
-
-class GcLLDescr_boehm(GcLLDescription):
-    moving_gc = False
-    gcrootmap = None
-
-    def __init__(self, gcdescr, translator):
-        GcLLDescription.__init__(self, gcdescr, translator)
-        # grab a pointer to the Boehm 'malloc' function
-        from pypy.rpython.tool import rffi_platform
-        compilation_info = rffi_platform.configure_boehm()
-
-        # Versions 6.x of libgc needs to use GC_local_malloc().
-        # Versions 7.x of libgc removed this function; GC_malloc() has
-        # the same behavior if libgc was compiled with
-        # THREAD_LOCAL_ALLOC.
-        class CConfig:
-            _compilation_info_ = compilation_info
-            HAS_LOCAL_MALLOC = rffi_platform.Has("GC_local_malloc")
-        config = rffi_platform.configure(CConfig)
-        if config['HAS_LOCAL_MALLOC']:
-            GC_MALLOC = "GC_local_malloc"
-        else:
-            GC_MALLOC = "GC_malloc"
-
-        malloc_fn_ptr = rffi.llexternal(GC_MALLOC,
-                                        [lltype.Signed], # size_t, but good enough
-                                        llmemory.GCREF,
-                                        compilation_info=compilation_info,
-                                        sandboxsafe=True,
-                                        _nowrapper=True)
-        self.funcptr_for_new = malloc_fn_ptr
-
-        # on some platform GC_init is required before any other
-        # GC_* functions, call it here for the benefit of tests
-        # XXX move this to tests
-        init_fn_ptr = rffi.llexternal("GC_init",
-                                      [], lltype.Void,
-                                      compilation_info=compilation_info,
-                                      sandboxsafe=True,
-                                      _nowrapper=True)
-
-        init_fn_ptr()
-
-    def gc_malloc(self, sizedescr):
-        assert isinstance(sizedescr, BaseSizeDescr)
-        return self.funcptr_for_new(sizedescr.size)
-
-    def gc_malloc_array(self, arraydescr, num_elem):
-        assert isinstance(arraydescr, BaseArrayDescr)
-        ofs_length = arraydescr.get_ofs_length(self.translate_support_code)
-        basesize = arraydescr.get_base_size(self.translate_support_code)
-        itemsize = arraydescr.get_item_size(self.translate_support_code)
-        size = basesize + itemsize * num_elem
-        res = self.funcptr_for_new(size)
-        rffi.cast(rffi.CArrayPtr(lltype.Signed), res)[ofs_length/WORD] = num_elem
-        return res
-
-    def gc_malloc_str(self, num_elem):
-        basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR,
-                                                   self.translate_support_code)
-        assert itemsize == 1
-        size = basesize + num_elem
-        res = self.funcptr_for_new(size)
-        rffi.cast(rffi.CArrayPtr(lltype.Signed), res)[ofs_length/WORD] = num_elem
-        return res
-
-    def gc_malloc_unicode(self, num_elem):
-        basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE,
-                                                   self.translate_support_code)
-        size = basesize + num_elem * itemsize
-        res = self.funcptr_for_new(size)
-        rffi.cast(rffi.CArrayPtr(lltype.Signed), res)[ofs_length/WORD] = num_elem
-        return res
-
-    def args_for_new(self, sizedescr):
-        assert isinstance(sizedescr, BaseSizeDescr)
-        return [sizedescr.size]
-
-    def get_funcptr_for_new(self):
-        return self.funcptr_for_new
-
-    get_funcptr_for_newarray = None
-    get_funcptr_for_newstr = None
-    get_funcptr_for_newunicode = None
+from pypy.rpython.memory import gctypelayout
+from pypy.rpython.memory.gctypelayout import _check_typeid
+from pypy.rpython.memory.gcheader import GCHeaderBuilder
+from pypy.rpython.memory.gctransform import framework
 
 
 # ____________________________________________________________
-# All code below is for the hybrid GC
+# All code below is for our framework GCs
 
 
-class GcRefList:
-    """Handles all references from the generated assembler to GC objects.
-    This is implemented as a nonmovable, but GC, list; the assembler contains
-    code that will (for now) always read from this list."""
-
-    GCREF_LIST = lltype.GcArray(llmemory.GCREF)     # followed by the GC
-
-    HASHTABLE = rffi.CArray(llmemory.Address)      # ignored by the GC
-    HASHTABLE_BITS = 10
-    HASHTABLE_SIZE = 1 << HASHTABLE_BITS
+class GcRefHandler:
+    """Handles all constant GCREFs stored in the assembler.
+    This includes the fact that some of these constants may end up stored
+    with an extra offset, e.g. as the address out of which a GETFIELD_GC
+    on them should fetch data.
+    """
+    CONSTGCREF_ARRAY = lltype.GcArray(("gcref", llmemory.GCREF),
+                                      ("addr", llmemory.Address))
+    gcrefarray_lengthoffset = llmemory.ArrayLengthOffset(CONSTGCREF_ARRAY)
+    gcrefarray_itemsoffset = llmemory.ArrayItemsOffset(CONSTGCREF_ARRAY)
+    gcrefarray_singleitemoffset = llmemory.ItemOffset(CONSTGCREF_ARRAY.OF)
+    gcrefarrayitem_gcref = llmemory.offsetof(CONSTGCREF_ARRAY.OF, "gcref")
+    gcrefarrayitem_addr  = llmemory.offsetof(CONSTGCREF_ARRAY.OF, "addr")
+
+    def __init__(self, layoutbuilder):
+        self.constgcref_array_type_id = layoutbuilder.get_type_id(
+            self.CONSTGCREF_ARRAY)
 
-    def initialize(self):
-        if we_are_translated(): n = 2000
-        else:                   n = 10    # tests only
-        self.list = self.alloc_gcref_list(n)
-        self.nextindex = 0
-        self.oldlists = []
-        # A pseudo dictionary: it is fixed size, and it may contain
-        # random nonsense after a collection moved the objects.  It is only
-        # used to avoid too many duplications in the GCREF_LISTs.
-        self.hashtable = lltype.malloc(self.HASHTABLE,
-                                       self.HASHTABLE_SIZE+1,
-                                       flavor='raw')
-        dummy = lltype.direct_ptradd(lltype.direct_arrayitems(self.hashtable),
-                                     self.HASHTABLE_SIZE)
-        dummy = llmemory.cast_ptr_to_adr(dummy)
-        for i in range(self.HASHTABLE_SIZE+1):
-            self.hashtable[i] = dummy
-
-    def alloc_gcref_list(self, n):
-        # Important: the GRREF_LISTs allocated are *non-movable*.  This
-        # requires support in the gc (only the hybrid GC supports it so far).
-        if we_are_translated():
-            list = rgc.malloc_nonmovable(self.GCREF_LIST, n)
-            assert list, "malloc_nonmovable failed!"
-        else:
-            list = lltype.malloc(self.GCREF_LIST, n)     # for tests only
-        return list
+    def _freeze_(self):
+        return True
 
-    def get_address_of_gcref(self, gcref):
-        assert lltype.typeOf(gcref) == llmemory.GCREF
-        # first look in the hashtable, using an inexact hash (fails after
-        # the object moves)
-        addr = llmemory.cast_ptr_to_adr(gcref)
-        hash = llmemory.cast_adr_to_int(addr)
-        hash -= hash >> self.HASHTABLE_BITS
-        hash &= self.HASHTABLE_SIZE - 1
-        addr_ref = self.hashtable[hash]
-        # the following test is safe anyway, because the addresses found
-        # in the hashtable are always the addresses of nonmovable stuff
-        # ('addr_ref' is an address inside self.list, not directly the
-        # address of a real moving GC object -- that's 'addr_ref.address[0]'.)
-        if addr_ref.address[0] == addr:
-            return addr_ref
-        # if it fails, add an entry to the list
-        if self.nextindex == len(self.list):
-            # reallocate first, increasing a bit the size every time
-            self.oldlists.append(self.list)
-            self.list = self.alloc_gcref_list(len(self.list) // 4 * 5)
-            self.nextindex = 0
-        # add it
-        index = self.nextindex
-        self.list[index] = gcref
-        addr_ref = lltype.direct_ptradd(lltype.direct_arrayitems(self.list),
-                                        index)
-        addr_ref = llmemory.cast_ptr_to_adr(addr_ref)
-        self.nextindex = index + 1
-        # record it in the hashtable
-        self.hashtable[hash] = addr_ref
-        return addr_ref
+    def start_tracing_varsized_part(self, obj, typeid):
+        """Called by the GC just before tracing the object 'obj'."""
+        if typeid == self.constgcref_array_type_id:
+            self.do_start_stop_tracing(obj, False)
+
+    def stop_tracing_varsized_part(self, obj, typeid):
+        """Called by the GC just after tracing the object 'obj'."""
+        if typeid == self.constgcref_array_type_id:
+            self.do_start_stop_tracing(obj, True)
+
+    def do_start_stop_tracing(self, obj, done):
+        # Before tracing an object of type CONSTGCREF_ARRAY
+        # (done=False), we take all addresses in the assembler and
+        # subtract the gcref from them.  This leaves the assembler in a
+        # broken state which is fixed by do_stop_tracing().  The numbers
+        # in the assembler now are just the offsets from the start of
+        # the objects.  After tracing (done=True), we add again the
+        # gcrefs to the addresses in the assembler, fixing up the
+        # numbers.
+        length = (obj + self.gcrefarray_lengthoffset).signed[0]
+        item = obj + self.gcrefarray_itemsoffset
+        while length > 0:
+            gcref = (item + self.gcrefarrayitem_gcref).address[0]
+            addr = (item + self.gcrefarrayitem_addr).address[0]
+            gcref = llmemory.cast_adr_to_int(gcref)
+            if done:
+                addr.signed[0] += gcref
+            else:
+                addr.signed[0] -= gcref
+            item += self.gcrefarray_singleitemoffset
+            length -= 1
+    do_start_stop_tracing._dont_inline_ = True
+    do_start_stop_tracing._annspecialcase_ = 'specialize:arg(2)'
 
 
 class GcRootMap_asmgcc:
@@ -327,19 +208,11 @@
 class GcLLDescr_framework(GcLLDescription):
 
     def __init__(self, gcdescr, translator, llop1=llop):
-        from pypy.rpython.memory.gctypelayout import _check_typeid
-        from pypy.rpython.memory.gcheader import GCHeaderBuilder
-        from pypy.rpython.memory.gctransform import framework
         GcLLDescription.__init__(self, gcdescr, translator)
         assert self.translate_support_code, "required with the framework GC"
         self.translator = translator
         self.llop1 = llop1
 
-        # we need the hybrid GC for GcRefList.alloc_gcref_list() to work
-        if gcdescr.config.translation.gc != 'hybrid':
-            raise NotImplementedError("--gc=%s not implemented with the JIT" %
-                                      (gcdescr.config.translation.gc,))
-
         # to find roots in the assembler, make a GcRootMap
         name = gcdescr.config.translation.gcrootfinder
         try:
@@ -349,17 +222,20 @@
                                       " with the JIT" % (name,))
         gcrootmap = cls()
         self.gcrootmap = gcrootmap
-        self.gcrefs = GcRefList()
-        self.single_gcref_descr = GcPtrFieldDescr(0)
 
         # make a TransformerLayoutBuilder and save it on the translator
         # where it can be fished and reused by the FrameworkGCTransformer
         self.layoutbuilder = framework.TransformerLayoutBuilder(translator)
         self.layoutbuilder.delay_encoding()
+        self.gcrefhandler = GcRefHandler(self.layoutbuilder)
         self.translator._jit2gc = {
             'layoutbuilder': self.layoutbuilder,
             'gcmapstart': lambda: gcrootmap.gcmapstart(),
             'gcmapend': lambda: gcrootmap.gcmapend(),
+            'start_tracing_varsized_part':
+                               self.gcrefhandler.start_tracing_varsized_part,
+            'stop_tracing_varsized_part':
+                               self.gcrefhandler.stop_tracing_varsized_part,
             }
         self.GCClass = self.layoutbuilder.GCClass
         self.moving_gc = self.GCClass.moving_gc
@@ -464,7 +340,6 @@
         return rffi.cast(lltype.Signed, fptr)
 
     def initialize(self):
-        self.gcrefs.initialize()
         self.gcrootmap.initialize()
 
     def init_size_descr(self, S, descr):
@@ -532,31 +407,26 @@
         # - Add COND_CALLs to the write barrier before SETFIELD_GC and
         #   SETARRAYITEM_GC operations.
         #
-        # - Remove all uses of ConstPtrs away from the assembler.
-        #   Idea: when running on a moving GC, we can't (easily) encode
-        #   the ConstPtrs in the assembler, because they can move at any
-        #   point in time.  Instead, we store them in 'gcrefs.list', a GC
-        #   but nonmovable list; and here, we modify 'operations' to
-        #   replace direct usage of ConstPtr with a BoxPtr loaded by a
-        #   GETFIELD_RAW from the array 'gcrefs.list'.
+        # - Remove "unsupported" uses of ConstPtrs away from the assembler.
+        #   The backend must support at least 'p = SAME_AS(ConstPtr(..))'
+        #   and might support more operations, like GETFIELD_GC.  It should
+        #   set GC_SUPPORTED_CONSTPTR to a dict of supported opnums.
+        #   Or, as in the x86 backend, it can directly support all usages of
+        #   ConstPtr and not need any rewrite at all (and then it should
+        #   set GC_SUPPORTED_CONSTPTR to True).
         #
         newops = []
         for op in operations:
             if op.opnum == rop.DEBUG_MERGE_POINT:
                 continue
-            # ---------- replace ConstPtrs with GETFIELD_RAW ----------
-            # xxx some performance issue here
-            for i in range(len(op.args)):
-                v = op.args[i]
-                if isinstance(v, ConstPtr) and bool(v.value):
-                    addr = self.gcrefs.get_address_of_gcref(v.value)
-                    # ^^^even for non-movable objects, to record their presence
-                    if rgc.can_move(v.value):
+            # ---------- replace ConstPtrs with SAME_AS ----------
+            if (cpu.GC_SUPPORTED_CONSTPTR is not True and
+                op.opnum not in cpu.GC_SUPPORTED_CONSTPTR):
+                for i in range(len(op.args)):
+                    v = op.args[i]
+                    if isinstance(v, ConstPtr) and bool(v.value):
                         box = BoxPtr(v.value)
-                        addr = cpu.cast_adr_to_int(addr)
-                        newops.append(ResOperation(rop.GETFIELD_RAW,
-                                                   [ConstInt(addr)], box,
-                                                   self.single_gcref_descr))
+                        newops.append(ResOperation(rop.SAME_AS, [v], box))
                         op.args[i] = box
             # ---------- write barrier for SETFIELD_GC ----------
             if op.opnum == rop.SETFIELD_GC:
@@ -595,18 +465,3 @@
 
     def has_write_barrier_class(self):
         return WriteBarrierDescr
-
-# ____________________________________________________________
-
-def get_ll_description(gcdescr, translator=None):
-    # translator is None if translate_support_code is False.
-    if gcdescr is not None:
-        name = gcdescr.config.translation.gctransformer
-    else:
-        name = "boehm"
-    try:
-        cls = globals()['GcLLDescr_' + name]
-    except KeyError:
-        raise NotImplementedError("GC transformer %r not supported by "
-                                  "the JIT backend" % (name,))
-    return cls(gcdescr, translator)

Modified: pypy/branch/jit-constptr/pypy/jit/backend/llsupport/test/test_gc.py
==============================================================================
--- pypy/branch/jit-constptr/pypy/jit/backend/llsupport/test/test_gc.py	(original)
+++ pypy/branch/jit-constptr/pypy/jit/backend/llsupport/test/test_gc.py	Mon Mar  8 16:22:14 2010
@@ -4,6 +4,7 @@
 from pypy.rpython.annlowlevel import llhelper
 from pypy.jit.backend.llsupport.descr import *
 from pypy.jit.backend.llsupport.gc import *
+from pypy.jit.backend.llsupport.gcframework import *
 from pypy.jit.backend.llsupport import symbolic
 from pypy.jit.metainterp.gc import get_description
 
@@ -46,19 +47,44 @@
 
 # ____________________________________________________________
 
-def test_GcRefList():
+def test_GcRefHandler():
+    class FakeLayoutBuilder:
+        def get_type_id(self, TYPE):
+            return 42
+    gcrefhandler = GcRefHandler(FakeLayoutBuilder())
+    gcrefhandler.start_tracing_varsized_part(None, 27)    # no effect
+    gcrefhandler.stop_tracing_varsized_part(None, 27)    # no effect
+    #
     S = lltype.GcStruct('S')
-    order = range(50) * 4
-    random.shuffle(order)
-    allocs = [lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S))
-              for i in range(50)]
-    allocs = [allocs[i] for i in order]
+    p0 = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S))
+    p1 = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S))
+    p = lltype.malloc(GcRefHandler.CONSTGCREF_ARRAY, 3)
+    #
+    ARRAY_SIGNED = lltype.Array(lltype.Signed)
+    test = lltype.malloc(ARRAY_SIGNED, 5, immortal=True)
+    test[2] = 123
+    test[3] = 456
+    test[4] = 789
+    #
+    p[0].gcref = p0
+    p[0].addr  = (llmemory.cast_ptr_to_adr(test) +
+                  llmemory.itemoffsetof(ARRAY_SIGNED, 2))
+    p[1].gcref = p0
+    p[1].addr  = (llmemory.cast_ptr_to_adr(test) +
+                  llmemory.itemoffsetof(ARRAY_SIGNED, 4))
+    p[2].gcref = p1
+    p[2].addr  = (llmemory.cast_ptr_to_adr(test) +
+                  llmemory.itemoffsetof(ARRAY_SIGNED, 3))
+    #
+    gcrefhandler.start_tracing_varsized_part(llmemory.cast_ptr_to_adr(p), 42)
+    assert test[2] == 123 - llmemory.cast_adr_to_int(p0)
+    assert test[3] == 456 - llmemory.cast_adr_to_int(p1)
+    assert test[4] == 789 - llmemory.cast_adr_to_int(p0)
     #
-    gcrefs = GcRefList()
-    gcrefs.initialize()
-    addrs = [gcrefs.get_address_of_gcref(ptr) for ptr in allocs]
-    for i in range(len(allocs)):
-        assert addrs[i].address[0] == llmemory.cast_ptr_to_adr(allocs[i])
+    gcrefhandler.stop_tracing_varsized_part(llmemory.cast_ptr_to_adr(p), 42)
+    assert test[2] == 123
+    assert test[3] == 456
+    assert test[4] == 789
 
 def test_GcRootMap_asmgcc():
     def frame_pos(n):
@@ -160,10 +186,7 @@
         class FakeTranslator:
             config = config_
         class FakeCPU:
-            def cast_adr_to_int(self, adr):
-                ptr = llmemory.cast_adr_to_ptr(adr, gc_ll_descr.WB_FUNCPTR)
-                assert ptr._obj._callable == llop1._write_barrier_failing_case
-                return 42
+            GC_SUPPORTED_CONSTPTR = {rop.SAME_AS: None}
         gcdescr = get_description(config_)
         translator = FakeTranslator()
         llop1 = FakeLLOp()
@@ -277,46 +300,40 @@
     def test_rewrite_assembler_1(self):
         # check rewriting of ConstPtrs
         class MyFakeCPU:
-            def cast_adr_to_int(self, adr):
-                assert adr == "some fake address"
-                return 43
-        class MyFakeGCRefList:
-            def get_address_of_gcref(self, s_gcref1):
-                assert s_gcref1 == s_gcref
-                return "some fake address"
+            GC_SUPPORTED_CONSTPTR = {rop.SAME_AS: None,
+                                     rop.OOISNOT: None}
         S = lltype.GcStruct('S')
         s = lltype.malloc(S)
         s_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
+        s2 = lltype.malloc(S)
+        s_gcref2 = lltype.cast_opaque_ptr(llmemory.GCREF, s2)
         v_random_box = BoxPtr()
         v_result = BoxInt()
+        v_result2 = BoxInt()
         operations = [
             ResOperation(rop.OOIS, [v_random_box, ConstPtr(s_gcref)],
                          v_result),
+            ResOperation(rop.OOISNOT, [v_random_box, ConstPtr(s_gcref2)],
+                         v_result2),
             ]
         gc_ll_descr = self.gc_ll_descr
-        gc_ll_descr.gcrefs = MyFakeGCRefList()
         gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations)
-        assert len(operations) == 2
-        assert operations[0].opnum == rop.GETFIELD_RAW
-        assert operations[0].args == [ConstInt(43)]
-        assert operations[0].descr == gc_ll_descr.single_gcref_descr
+        assert len(operations) == 3
+        assert operations[0].opnum == rop.SAME_AS
+        assert operations[0].args == [ConstPtr(s_gcref)]
         v_box = operations[0].result
         assert isinstance(v_box, BoxPtr)
         assert operations[1].opnum == rop.OOIS
         assert operations[1].args == [v_random_box, v_box]
         assert operations[1].result == v_result
+        assert operations[2].opnum == rop.OOISNOT
+        assert operations[2].args == [v_random_box, ConstPtr(s_gcref2)]
+        assert operations[2].result == v_result2
 
-    def test_rewrite_assembler_1_cannot_move(self):
-        # check rewriting of ConstPtrs
+    def test_rewrite_assembler_1_all_supported(self):
+        # check no rewriting of ConstPtrs if the cpu supports it fully
         class MyFakeCPU:
-            def cast_adr_to_int(self, adr):
-                xxx    # should not be called
-        class MyFakeGCRefList:
-            def get_address_of_gcref(self, s_gcref1):
-                seen.append(s_gcref1)
-                assert s_gcref1 == s_gcref
-                return "some fake address"
-        seen = []
+            GC_SUPPORTED_CONSTPTR = True
         S = lltype.GcStruct('S')
         s = lltype.malloc(S)
         s_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
@@ -327,20 +344,11 @@
                          v_result),
             ]
         gc_ll_descr = self.gc_ll_descr
-        gc_ll_descr.gcrefs = MyFakeGCRefList()
-        old_can_move = rgc.can_move
-        try:
-            rgc.can_move = lambda s: False
-            gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations)
-        finally:
-            rgc.can_move = old_can_move
+        gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations)
         assert len(operations) == 1
         assert operations[0].opnum == rop.OOIS
         assert operations[0].args == [v_random_box, ConstPtr(s_gcref)]
         assert operations[0].result == v_result
-        # check that s_gcref gets added to the list anyway, to make sure
-        # that the GC sees it
-        assert seen == [s_gcref]
 
     def test_rewrite_assembler_2(self):
         # check write barriers before SETFIELD_GC

Modified: pypy/branch/jit-constptr/pypy/jit/backend/x86/runner.py
==============================================================================
--- pypy/branch/jit-constptr/pypy/jit/backend/x86/runner.py	(original)
+++ pypy/branch/jit-constptr/pypy/jit/backend/x86/runner.py	Mon Mar  8 16:22:14 2010
@@ -13,6 +13,7 @@
 class CPU386(AbstractLLCPU):
     debug = True
     supports_floats = True
+    GC_SUPPORTED_CONSTPTR = True
 
     BOOTSTRAP_TP = lltype.FuncType([], lltype.Signed)
     dont_keepalive_stuff = False # for tests

Modified: pypy/branch/jit-constptr/pypy/jit/backend/x86/test/test_zrpy_gc.py
==============================================================================
--- pypy/branch/jit-constptr/pypy/jit/backend/x86/test/test_zrpy_gc.py	(original)
+++ pypy/branch/jit-constptr/pypy/jit/backend/x86/test/test_zrpy_gc.py	Mon Mar  8 16:22:14 2010
@@ -14,7 +14,6 @@
 from pypy.rlib.jit import JitDriver, OPTIMIZER_SIMPLE, dont_look_inside
 from pypy.rlib.jit import purefunction
 from pypy.jit.backend.x86.runner import CPU386
-from pypy.jit.backend.llsupport.gc import GcRefList, GcRootMap_asmgcc
 from pypy.tool.udir import udir
 
 class X(object):

Modified: pypy/branch/jit-constptr/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/branch/jit-constptr/pypy/rpython/memory/gc/base.py	(original)
+++ pypy/branch/jit-constptr/pypy/rpython/memory/gc/base.py	Mon Mar  8 16:22:14 2010
@@ -25,6 +25,9 @@
         self.AddressDeque = get_address_deque(chunk_size)
         self.AddressDict = AddressDict
         self.config = config
+        # hooks used by the JIT:
+        self.start_tracing_varsized_part = lambda obj, typeid: None
+        self.stop_tracing_varsized_part = lambda obj, typeid: None
 
     def setup(self):
         # all runtime mutable values' setup should happen here
@@ -177,6 +180,7 @@
                 callback(item, arg)
             i += 1
         if self.has_gcptr_in_varsize(typeid):
+            self.start_tracing_varsized_part(obj, typeid)
             item = obj + self.varsize_offset_to_variable_part(typeid)
             length = (obj + self.varsize_offset_to_length(typeid)).signed[0]
             offsets = self.varsize_offsets_to_gcpointers_in_var_part(typeid)
@@ -190,6 +194,7 @@
                     j += 1
                 item += itemlength
                 length -= 1
+            self.stop_tracing_varsized_part(obj, typeid)
     trace._annspecialcase_ = 'specialize:arg(2)'
 
     def points_to_valid_gc_object(self, addr):

Modified: pypy/branch/jit-constptr/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/branch/jit-constptr/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/branch/jit-constptr/pypy/rpython/memory/gctransform/framework.py	Mon Mar  8 16:22:14 2010
@@ -181,6 +181,12 @@
         self.num_pushs = 0
         self.write_barrier_calls = 0
 
+        if hasattr(translator, '_jit2gc'):
+            fn = translator._jit2gc['start_tracing_varsized_part']
+            gcdata.gc.start_tracing_varsized_part = fn
+            fn = translator._jit2gc['stop_tracing_varsized_part']
+            gcdata.gc.stop_tracing_varsized_part = fn
+
         def frameworkgc_setup():
             # run-time initialization code
             root_walker.setup_root_walker()



More information about the Pypy-commit mailing list