[pypy-svn] r49785 - pypy/dist/pypy/rpython/memory

arigo at codespeak.net arigo at codespeak.net
Fri Dec 14 15:50:25 CET 2007


Author: arigo
Date: Fri Dec 14 15:50:25 2007
New Revision: 49785

Modified:
   pypy/dist/pypy/rpython/memory/gctypelayout.py
Log:
Experimental: encode the Bool flags as combination of bits on the typeid.
Small speed-up only.


Modified: pypy/dist/pypy/rpython/memory/gctypelayout.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctypelayout.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctypelayout.py	Fri Dec 14 15:50:25 2007
@@ -5,9 +5,9 @@
 class GCData(object):
     """The GC information tables, and the query functions that the GC
     calls to decode their content.  The encoding of this information
-    is done by TypeLayoutBuilder.get_type_id().  These two places
-    should be in sync, obviously, but in principle no other code
-    should depend on the details of the encoding in TYPE_INFO.
+    is done by encode_type_shape().  These two places should be in sync,
+    obviously, but in principle no other code should depend on the
+    details of the encoding in TYPE_INFO.
     """
     _alloc_flavor_ = 'raw'
 
@@ -17,9 +17,6 @@
 
     # structure describing the layout of a typeid
     TYPE_INFO = lltype.Struct("type_info",
-        ("isvarsize",      lltype.Bool),
-        ("gcptrinvarsize", lltype.Bool),
-        ("gcarrayofgcptr", lltype.Bool),
         ("finalizer",      FINALIZERTYPE),
         ("fixedsize",      lltype.Signed),
         ("ofstoptrs",      lltype.Ptr(OFFSETS_TO_GC_PTR)),
@@ -39,15 +36,16 @@
 
     def q_is_varsize(self, typeid):
         ll_assert(typeid > 0, "invalid type_id")
-        return self.type_info_table[typeid].isvarsize
+        return (typeid & T_IS_FIXSIZE) == 0
 
     def q_has_gcptr_in_varsize(self, typeid):
         ll_assert(typeid > 0, "invalid type_id")
-        return self.type_info_table[typeid].gcptrinvarsize
+        return (typeid & (T_IS_FIXSIZE|T_NO_GCPTR_IN_VARSIZE)) == 0
 
     def q_is_gcarrayofgcptr(self, typeid):
         ll_assert(typeid > 0, "invalid type_id")
-        return self.type_info_table[typeid].gcarrayofgcptr
+        return (typeid &
+                (T_IS_FIXSIZE|T_NO_GCPTR_IN_VARSIZE|T_NOT_SIMPLE_GCARRAY)) == 0
 
     def q_finalizer(self, typeid):
         ll_assert(typeid > 0, "invalid type_id")
@@ -95,16 +93,107 @@
             self.q_varsize_offsets_to_gcpointers_in_var_part,
             self.q_weakpointer_offset)
 
+# For the q_xxx functions that return flags, we use bit patterns
+# in the typeid instead of entries in the type_info_table.  The
+# following flag combinations are used (the idea being that it's
+# very fast on CPUs to check if all flags in a set are all zero):
+
+#   * if T_IS_FIXSIZE is set, the gc object is not var-sized
+#   * if T_IS_FIXSIZE and T_NO_GCPTR_IN_VARSIZE are both cleared,
+#           there are gc ptrs in the var-sized part
+#   * if T_IS_FIXSIZE, T_NO_GCPTR_IN_VARSIZE and T_NOT_SIMPLE_GCARRAY
+#           are all cleared, the shape is just like GcArray(gcptr)
+
+T_IS_FIXSIZE          = 0x4
+T_NO_GCPTR_IN_VARSIZE = 0x2
+T_NOT_SIMPLE_GCARRAY  = 0x1
+
+def get_typeid_bitmask(TYPE):
+    """Return the bits that we would like to be set or cleared in the type_id
+    corresponding to TYPE.  This returns (mask, expected_value), where
+    the condition is that 'type_id & mask == expected_value'.
+    """
+    if not TYPE._is_varsize():
+        return (T_IS_FIXSIZE, T_IS_FIXSIZE)     # not var-sized
+
+    if (isinstance(TYPE, lltype.GcArray)
+        and isinstance(TYPE.OF, lltype.Ptr)
+        and TYPE.OF.TO._gckind == 'gc'):
+        # a simple GcArray(gcptr)
+        return (T_IS_FIXSIZE|T_NO_GCPTR_IN_VARSIZE|T_NOT_SIMPLE_GCARRAY, 0)
+
+    if isinstance(TYPE, lltype.Struct):
+        ARRAY = TYPE._flds[TYPE._arrayfld]
+    else:
+        ARRAY = TYPE
+    assert isinstance(ARRAY, lltype.Array)
+    if ARRAY.OF != lltype.Void and len(offsets_to_gc_pointers(ARRAY.OF)) > 0:
+        # var-sized, with gc pointers in the variable part
+        return (T_IS_FIXSIZE|T_NO_GCPTR_IN_VARSIZE|T_NOT_SIMPLE_GCARRAY,
+                T_NOT_SIMPLE_GCARRAY)
+    else:
+        # var-sized, but no gc pointer in the variable part
+        return (T_IS_FIXSIZE|T_NO_GCPTR_IN_VARSIZE, T_NO_GCPTR_IN_VARSIZE)
+
+
+def encode_type_shape(builder, info, TYPE):
+    """Encode the shape of the TYPE into the TYPE_INFO structure 'info'."""
+    offsets = offsets_to_gc_pointers(TYPE)
+    info.ofstoptrs = builder.offsets2table(offsets, TYPE)
+    info.finalizer = builder.make_finalizer_funcptr_for_type(TYPE)
+    info.weakptrofs = weakpointer_offset(TYPE)
+    if not TYPE._is_varsize():
+        #info.isvarsize = False
+        #info.gcptrinvarsize = False
+        info.fixedsize = llarena.round_up_for_allocation(
+            llmemory.sizeof(TYPE))
+        info.ofstolength = -1
+        # note about round_up_for_allocation(): in the 'info' table
+        # we put a rounded-up size only for fixed-size objects.  For
+        # varsize ones, the GC must anyway compute the size at run-time
+        # and round up that result.
+    else:
+        #info.isvarsize = True
+        info.fixedsize = llmemory.sizeof(TYPE, 0)
+        if isinstance(TYPE, lltype.Struct):
+            ARRAY = TYPE._flds[TYPE._arrayfld]
+            ofs1 = llmemory.offsetof(TYPE, TYPE._arrayfld)
+            info.ofstolength = ofs1 + llmemory.ArrayLengthOffset(ARRAY)
+            if ARRAY.OF != lltype.Void:
+                info.ofstovar = ofs1 + llmemory.itemoffsetof(ARRAY, 0)
+            else:
+                info.fixedsize = ofs1 + llmemory.sizeof(lltype.Signed)
+            # XXX we probably don't need isrpystring any more
+            if ARRAY._hints.get('isrpystring'):
+                info.fixedsize = llmemory.sizeof(TYPE, 1)
+        else:
+            ARRAY = TYPE
+            info.ofstolength = llmemory.ArrayLengthOffset(ARRAY)
+            if ARRAY.OF != lltype.Void:
+                info.ofstovar = llmemory.itemoffsetof(TYPE, 0)
+            else:
+                info.fixedsize = (llmemory.ArrayLengthOffset(ARRAY) +
+                                  llmemory.sizeof(lltype.Signed))
+        assert isinstance(ARRAY, lltype.Array)
+        if ARRAY.OF != lltype.Void:
+            offsets = offsets_to_gc_pointers(ARRAY.OF)
+        else:
+            offsets = ()
+        info.varofstoptrs = builder.offsets2table(offsets, ARRAY.OF)
+        info.varitemsize = llmemory.sizeof(ARRAY.OF)
+        #info.gcptrinvarsize = len(offsets) > 0
+    #info.gcarrayofgcptr = (isinstance(TYPE, lltype.GcArray)
+    #                       and isinstance(TYPE.OF, lltype.Ptr)
+    #                       and TYPE.OF.TO._gckind == 'gc')
+
 # ____________________________________________________________
 
+
 class TypeLayoutBuilder(object):
     can_add_new_types = True
 
     def __init__(self):
-        dummy = lltype.malloc(GCData.TYPE_INFO, immortal=True, zero=True)
-        dummy.weakptrofs = -1
-        dummy.ofstolength = -1
-        self.type_info_list = [dummy]   # don't use typeid 0, helps debugging
+        self.type_info_list = [None]   # don't use typeid 0, helps debugging
         self.id_of_type = {}      # {LLTYPE: type_id}
         self.seen_roots = {}
         # the following are lists of addresses of gc pointers living inside the
@@ -116,6 +205,7 @@
         self.addresses_of_static_ptrs_in_nongc = []
         self.finalizer_funcptrs = {}
         self.offsettable_cache = {}
+        self.next_typeid_cache = {}
 
     def get_type_id(self, TYPE):
         try:
@@ -123,63 +213,29 @@
         except KeyError:
             assert self.can_add_new_types
             assert isinstance(TYPE, (lltype.GcStruct, lltype.GcArray))
-            # Record the new type_id description as a small dict for now.
-            # The framework gc transformer will turn it into a
-            # Struct("type_info") in flatten_table().
-            type_id = len(self.type_info_list)
+            # Record the new type_id description as a TYPE_INFO structure.
+            # It goes into a list for now, which will be turned into a
+            # TYPE_INFO_TABLE in flatten_table() by the gc transformer.
+
+            # pick the next type_id with the correct bits set or cleared
+            mask, expected = get_typeid_bitmask(TYPE)
+            type_id = self.next_typeid_cache.get((mask, expected), 1)
+            while True:
+                if type_id == len(self.type_info_list):
+                    self.type_info_list.append(None)
+                if (self.type_info_list[type_id] is None and
+                    (type_id & mask) == expected):
+                    break         # can use this type_id
+                else:
+                    type_id += 1  # continue searching
+            self.next_typeid_cache[mask, expected] = type_id + 1
             assert type_id & 0xffff == type_id # make sure it fits into 2 bytes
+
+            # build the TYPE_INFO structure
             info = lltype.malloc(GCData.TYPE_INFO, immortal=True, zero=True)
-            self.type_info_list.append(info)
+            encode_type_shape(self, info, TYPE)
+            self.type_info_list[type_id] = info
             self.id_of_type[TYPE] = type_id
-            offsets = offsets_to_gc_pointers(TYPE)
-            info.ofstoptrs = self.offsets2table(offsets, TYPE)
-            info.finalizer = self.make_finalizer_funcptr_for_type(TYPE)
-            info.weakptrofs = weakpointer_offset(TYPE)
-            if not TYPE._is_varsize():
-                info.isvarsize = False
-                info.gcptrinvarsize = False
-                info.fixedsize = llarena.round_up_for_allocation(
-                    llmemory.sizeof(TYPE))
-                info.ofstolength = -1
-                # note about round_up_for_allocation(): in the 'info' table
-                # we put a rounded-up size only for fixed-size objects.  For
-                # varsize ones, the GC must anyway compute the size at run-time
-                # and round up that result.
-            else:
-                info.isvarsize = True
-                info.fixedsize = llmemory.sizeof(TYPE, 0)
-                if isinstance(TYPE, lltype.Struct):
-                    ARRAY = TYPE._flds[TYPE._arrayfld]
-                    ofs1 = llmemory.offsetof(TYPE, TYPE._arrayfld)
-                    info.ofstolength = ofs1 + llmemory.ArrayLengthOffset(ARRAY)
-                    if ARRAY.OF != lltype.Void:
-                        info.ofstovar = ofs1 + llmemory.itemoffsetof(ARRAY, 0)
-                    else:
-                        info.fixedsize = ofs1 + llmemory.sizeof(lltype.Signed)
-                    # XXX we probably don't need isrpystring any more
-                    if ARRAY._hints.get('isrpystring'):
-                        info.fixedsize = llmemory.sizeof(TYPE, 1)
-                else:
-                    ARRAY = TYPE
-                    info.ofstolength = llmemory.ArrayLengthOffset(ARRAY)
-                    if ARRAY.OF != lltype.Void:
-                        info.ofstovar = llmemory.itemoffsetof(TYPE, 0)
-                    else:
-                        info.fixedsize = (llmemory.ArrayLengthOffset(ARRAY) +
-                                          llmemory.sizeof(lltype.Signed))
-                assert isinstance(ARRAY, lltype.Array)
-                if ARRAY.OF != lltype.Void:
-                    offsets = offsets_to_gc_pointers(ARRAY.OF)
-                else:
-                    offsets = ()
-                info.varofstoptrs = self.offsets2table(offsets, ARRAY.OF)
-                info.varitemsize = llmemory.sizeof(ARRAY.OF)
-                info.gcptrinvarsize = len(offsets) > 0
-            # if the type is of the shape GcArray(gcptr) then we record,
-            # for now, a flag in the 'info'.  XXX could use a bit in typeid
-            info.gcarrayofgcptr = (isinstance(TYPE, lltype.GcArray)
-                                   and isinstance(TYPE.OF, lltype.Ptr)
-                                   and TYPE.OF.TO._gckind == 'gc')
             return type_id
 
     def offsets2table(self, offsets, TYPE):
@@ -200,8 +256,12 @@
                               immortal=True)
         fieldnames = GCData.TYPE_INFO._names
         for tableentry, newcontent in zip(table, self.type_info_list):
-            for name in fieldnames:
-                setattr(tableentry, name, getattr(newcontent, name))
+            if newcontent is None:    # empty entry
+                tableentry.weakptrofs = -1
+                tableentry.ofstolength = -1
+            else:
+                for name in fieldnames:
+                    setattr(tableentry, name, getattr(newcontent, name))
         return table
 
     def finalizer_funcptr_for_type(self, TYPE):



More information about the Pypy-commit mailing list