[pypy-commit] pypy strbuf-as-buffer: extend and pass test to check get_raw_address_of_string. it creates a initialized shadow object. at the first collection that tries to move the original object out of nursery, the shadow will be used (without copying the memory of the original object)

plan_rich pypy.commits at gmail.com
Tue Dec 20 06:30:11 EST 2016


Author: Richard Plangger <planrichi at gmail.com>
Branch: strbuf-as-buffer
Changeset: r89196:b8bb9cf9e713
Date: 2016-12-20 12:29 +0100
http://bitbucket.org/pypy/pypy/changeset/b8bb9cf9e713/

Log:	extend and pass test to check get_raw_address_of_string. it creates
	a initialized shadow object. at the first collection that tries to
	move the original object out of nursery, the shadow will be used
	(without copying the memory of the original object)

diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -158,7 +158,11 @@
 # record that ignore_finalizer() has been called
 GCFLAG_IGNORE_FINALIZER = first_gcflag << 10
 
-_GCFLAG_FIRST_UNUSED = first_gcflag << 11    # the first unused bit
+# shadow objects can have its memory initialized when it is created.
+# It does not need an additional copy in trace out
+GCFLAG_SHADOW_INITIALIZED   = first_gcflag << 11
+
+_GCFLAG_FIRST_UNUSED = first_gcflag << 12    # the first unused bit
 
 
 # States for the incremental GC
@@ -730,27 +734,15 @@
         return llmemory.cast_adr_to_ptr(obj, llmemory.GCREF)
 
     def move_out_of_nursery(self, obj):
-        #
-        size_gc_header = self.gcheaderbuilder.size_gc_header
-        totalsize = size_gc_header + self.get_size(obj)
-        self.nursery_surviving_size += raw_malloc_usage(totalsize)
-        newhdr = self._malloc_out_of_nursery(totalsize)
-        llmemory.raw_memcopy(obj - size_gc_header, newhdr, totalsize)
+        # called twice, it should return the same shadow object,
+        # and not creating another shadow object
+        if self.header(obj).tid & GCFLAG_HAS_SHADOW:
+            shadow = self.nursery_objects_shadows.get(obj)
+            ll_assert(shadow != llmemory.NULL,
+                      "GCFLAG_HAS_SHADOW but no shadow found")
+            return shadow
 
-        # Set the old object's tid to -42 (containing all flags) and
-        # replace the old object's content with the target address.
-        # A bit of no-ops to convince llarena that we are changing
-        # the layout, in non-translated versions.
-        typeid = self.get_type_id(obj)
-        obj = llarena.getfakearenaaddress(obj)
-        llarena.arena_reset(obj - size_gc_header, totalsize, 0)
-        llarena.arena_reserve(obj - size_gc_header,
-                              size_gc_header + llmemory.sizeof(FORWARDSTUB))
-        self.header(obj).tid = -42
-        newobj = newhdr + size_gc_header
-        llmemory.cast_adr_to_ptr(obj, FORWARDSTUBPTR).forw = newobj
-        return llmemory.cast_adr_to_ptr(newobj, llmemory.GCREF)
-
+        return self._allocate_shadow(obj, copy=True)
 
     def collect(self, gen=2):
         """Do a minor (gen=0), start a major (gen=1), or do a full
@@ -2004,6 +1996,9 @@
                 and self.young_rawmalloced_objects.contains(obj)):
                 self._visit_young_rawmalloced_object(obj)
             return
+        # copy the contents of the object? usually yes, but not for some
+        # shadow objects
+        copy = True
         #
         size_gc_header = self.gcheaderbuilder.size_gc_header
         if self.header(obj).tid & (GCFLAG_HAS_SHADOW | GCFLAG_PINNED) == 0:
@@ -2059,13 +2054,18 @@
             # Remove the flag GCFLAG_HAS_SHADOW, so that it doesn't get
             # copied to the shadow itself.
             self.header(obj).tid &= ~GCFLAG_HAS_SHADOW
+            tid = self.header(obj).tid
+            if (tid & GCFLAG_SHADOW_INITIALIZED) != 0:
+                copy = False
+                self.header(obj).tid &= ~GCFLAG_SHADOW_INITIALIZED
             #
             totalsize = size_gc_header + self.get_size(obj)
             self.nursery_surviving_size += raw_malloc_usage(totalsize)
         #
         # Copy it.  Note that references to other objects in the
         # nursery are kept unchanged in this step.
-        llmemory.raw_memcopy(obj - size_gc_header, newhdr, totalsize)
+        if copy:
+            llmemory.raw_memcopy(obj - size_gc_header, newhdr, totalsize)
         #
         # Set the old object's tid to -42 (containing all flags) and
         # replace the old object's content with the target address.
@@ -2592,7 +2592,8 @@
     # ----------
     # id() and identityhash() support
 
-    def _allocate_shadow(self, obj):
+    @specialize.arg(2)
+    def _allocate_shadow(self, obj, copy=False):
         size_gc_header = self.gcheaderbuilder.size_gc_header
         size = self.get_size(obj)
         shadowhdr = self._malloc_out_of_nursery(size_gc_header +
@@ -2614,6 +2615,12 @@
         #
         self.header(obj).tid |= GCFLAG_HAS_SHADOW
         self.nursery_objects_shadows.setitem(obj, shadow)
+
+        if copy:
+            self.header(obj).tid |= GCFLAG_SHADOW_INITIALIZED
+            totalsize = size_gc_header + self.get_size(obj)
+            llmemory.raw_memcopy(obj - size_gc_header, shadow, totalsize)
+
         return shadow
 
     def _find_shadow(self, obj):
@@ -3151,4 +3158,3 @@
             if surviving_dict:
                 surviving_dict.insertclean(obj, pyobject)
         else:
-            self._rrc_free(pyobject)
diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -1596,8 +1596,11 @@
         if self.move_out_of_nursery_ptr is not None:
             v_adr = hop.genop("cast_ptr_to_adr", [hop.spaceop.args[0]],
                               resulttype=llmemory.Address)
-            hop.genop("direct_call", [self.move_out_of_nursery_ptr,
-                                      self.c_const_gc, v_adr])
+            v_ret = hop.genop("direct_call", [self.move_out_of_nursery_ptr,
+                                      self.c_const_gc, v_adr],
+                                      resulttype=llmemory.Address)
+            hop.genop("cast_adr_to_ptr", [v_ret],
+                      resultvar = hop.spaceop.result)
 
 
 
diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -537,11 +537,23 @@
 
 @jit.dont_look_inside
 def move_out_of_nursery(obj):
-    """This object should move to the second generation (out of nursery).
-    The object will not move, anymore after this operation succeeded.
+    """ Returns another object which is a copy of obj; but at any point
+        (either now or in the future) the returned object might suddenly
+        become identical to the one returned.
+
+        NOTE: Only use for immutable objects!
     """
-    from rpython.rtyper.lltypesystem.lloperation import llop
-    llop.gc_move_out_of_nursery(obj)
+    pass
+
+class MoveOutOfNurseryEntry(ExtRegistryEntry):
+    _about_ = move_out_of_nursery
+
+    def compute_result_annotation(self, s_obj):
+        return s_obj
+
+    def specialize_call(self, hop):
+        hop.exception_cannot_occur()
+        return hop.genop('gc_move_out_of_nursery', hop.args_v, resulttype=hop.r_result)
 
 # ____________________________________________________________
 
diff --git a/rpython/rtyper/lltypesystem/rffi.py b/rpython/rtyper/lltypesystem/rffi.py
--- a/rpython/rtyper/lltypesystem/rffi.py
+++ b/rpython/rtyper/lltypesystem/rffi.py
@@ -1336,16 +1336,16 @@
     referencing it goes out of scope.
     """
     assert isinstance(string, str)
-    from rpython.rtyper.annlowlevel import llstr
+    from rpython.rtyper.annlowlevel import llstr, hlstr
     from rpython.rtyper.lltypesystem.rstr import STR
     from rpython.rtyper.lltypesystem import llmemory
     from rpython.rlib import rgc
 
     if we_are_translated():
         if rgc.can_move(string):
+            # create a shadow object that is exposed
             string = rgc.move_out_of_nursery(string)
 
-        assert not rgc.can_move(string)
         # string cannot move! just return the address then!
         lldata = llstr(string)
         data_start = (llmemory.cast_ptr_to_adr(lldata) +
diff --git a/rpython/rtyper/lltypesystem/test/test_ztranslated.py b/rpython/rtyper/lltypesystem/test/test_ztranslated.py
--- a/rpython/rtyper/lltypesystem/test/test_ztranslated.py
+++ b/rpython/rtyper/lltypesystem/test/test_ztranslated.py
@@ -1,27 +1,39 @@
-import time, os, sys
-import py
+import sys
 import gc
-from rpython.tool.udir import udir
-from rpython.rlib import rvmprof, rthread
 from rpython.translator.c.test.test_genc import compile
-from rpython.rlib.nonconst import NonConstant
 from rpython.rtyper.lltypesystem import rffi
+from rpython.rtyper.lltypesystem import lltype
+from rpython.rtyper.annlowlevel import llstr, hlstr
+from rpython.rtyper.lltypesystem.lloperation import llop
 
 def setup_module(mod):
     pass
 
+def debug_assert(boolresult, msg):
+    if not boolresult:
+        llop.debug_print(lltype.Void, "\n\nassert failed: %s\n\n" % msg)
+        assert boolresult
+
 def use_str():
-    mystr = b"abc"
+    mystr = b'abc'[:]
     ptr = rffi.get_raw_address_of_string(mystr)
-    assert ptr[0] == 79
+    ptr2 = rffi.get_raw_address_of_string(mystr)
+    debug_assert(ptr == ptr2, "ptr != ptr2")
+    debug_assert(ptr[0] == b'a', "notnurseryadr[0] == b'a' is is %s" % ptr[0])
+    ptr[0] = b'x' # oh no no, in real programs nobody is allowed to modify that
+    debug_assert(mystr[0] in b'ax', "mystr[0] in b'ax'")
+    debug_assert(ptr[0] == b'x', "notnurseryadr[0] == b'x'")
     gc.collect()
-    assert ptr[0] == 79
+    nptr = rffi.get_raw_address_of_string(mystr)
+    debug_assert(nptr == ptr, "second call to mystr must return the same ptr")
+    debug_assert(ptr[0] == b'x', "failure a")
+    debug_assert(nptr[0] == b'x', "failure b")
     mystr = None
 
-
-
 def main(argv=[]):
     use_str()
+    llop.debug_print(lltype.Void, "passed first call to use_str")
+    gc.collect()
     return 0
 
 # ____________________________________________________________


More information about the pypy-commit mailing list