[pypy-commit] pypy remove-objspace-options: Now, if an RPython program uses weakrefs when translation.rweakref is

arigo pypy.commits at gmail.com
Mon Apr 25 06:33:05 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: remove-objspace-options
Changeset: r83855:0713002caf76
Date: 2016-04-25 12:31 +0200
http://bitbucket.org/pypy/pypy/changeset/0713002caf76/

Log:	Now, if an RPython program uses weakrefs when translation.rweakref
	is False, we don't get a translation crash; instead we get non-weak
	references.

diff --git a/rpython/memory/gctransform/boehm.py b/rpython/memory/gctransform/boehm.py
--- a/rpython/memory/gctransform/boehm.py
+++ b/rpython/memory/gctransform/boehm.py
@@ -46,11 +46,12 @@
                 ll_malloc_varsize_no_length, [lltype.Signed]*3, llmemory.Address, inline=False)
             self.malloc_varsize_ptr = self.inittime_helper(
                 ll_malloc_varsize, [lltype.Signed]*4, llmemory.Address, inline=False)
-            self.weakref_create_ptr = self.inittime_helper(
-                ll_weakref_create, [llmemory.Address], llmemory.WeakRefPtr,
-                inline=False)
-            self.weakref_deref_ptr = self.inittime_helper(
-                ll_weakref_deref, [llmemory.WeakRefPtr], llmemory.Address)
+            if self.translator.config.translation.rweakref:
+                self.weakref_create_ptr = self.inittime_helper(
+                    ll_weakref_create, [llmemory.Address], llmemory.WeakRefPtr,
+                    inline=False)
+                self.weakref_deref_ptr = self.inittime_helper(
+                    ll_weakref_deref, [llmemory.WeakRefPtr], llmemory.Address)
             self.identityhash_ptr = self.inittime_helper(
                 ll_identityhash, [llmemory.Address], lltype.Signed,
                 inline=False)
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
@@ -236,8 +236,9 @@
                                                annmodel.s_None)
 
         self.annotate_walker_functions(getfn)
-        self.weakref_deref_ptr = self.inittime_helper(
-            ll_weakref_deref, [llmemory.WeakRefPtr], llmemory.Address)
+        if translator.config.translation.rweakref:
+            self.weakref_deref_ptr = self.inittime_helper(
+                ll_weakref_deref, [llmemory.WeakRefPtr], llmemory.Address)
 
         classdef = bk.getuniqueclassdef(GCClass)
         s_gc = annmodel.SomeInstance(classdef)
diff --git a/rpython/rlib/rweakref.py b/rpython/rlib/rweakref.py
--- a/rpython/rlib/rweakref.py
+++ b/rpython/rlib/rweakref.py
@@ -7,7 +7,14 @@
 import weakref
 from rpython.annotator.model import UnionError
 
-ref = weakref.ref    # basic regular weakrefs are supported in RPython
+
+# Basic regular weakrefs are supported in RPython.
+# Note that if 'translation.rweakref' is False, they will
+# still work, but be implemented as a strong reference.
+# This case is useful for developing new GCs, for example.
+
+ref = weakref.ref
+
 
 def has_weakref_support():
     return True      # returns False if --no-translation-rweakref
diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py
--- a/rpython/rtyper/llinterp.py
+++ b/rpython/rtyper/llinterp.py
@@ -782,17 +782,21 @@
     def op_weakref_create(self, v_obj):
         def objgetter():    # special support for gcwrapper.py
             return self.getval(v_obj)
+        assert self.llinterpreter.typer.getconfig().translation.rweakref
         return self.heap.weakref_create_getlazy(objgetter)
     op_weakref_create.specialform = True
 
     def op_weakref_deref(self, PTRTYPE, obj):
+        assert self.llinterpreter.typer.getconfig().translation.rweakref
         return self.heap.weakref_deref(PTRTYPE, obj)
     op_weakref_deref.need_result_type = True
 
     def op_cast_ptr_to_weakrefptr(self, obj):
+        assert self.llinterpreter.typer.getconfig().translation.rweakref
         return llmemory.cast_ptr_to_weakrefptr(obj)
 
     def op_cast_weakrefptr_to_ptr(self, PTRTYPE, obj):
+        assert self.llinterpreter.typer.getconfig().translation.rweakref
         return llmemory.cast_weakrefptr_to_ptr(PTRTYPE, obj)
     op_cast_weakrefptr_to_ptr.need_result_type = True
 
diff --git a/rpython/rtyper/rbuiltin.py b/rpython/rtyper/rbuiltin.py
--- a/rpython/rtyper/rbuiltin.py
+++ b/rpython/rtyper/rbuiltin.py
@@ -735,12 +735,21 @@
 @typer_for(llmemory.weakref_create)
 @typer_for(weakref.ref)
 def rtype_weakref_create(hop):
-    vlist = hop.inputargs(hop.args_r[0])
+    from rpython.rtyper.rweakref import BaseWeakRefRepr
+
+    v_inst, = hop.inputargs(hop.args_r[0])
     hop.exception_cannot_occur()
-    return hop.genop('weakref_create', vlist, resulttype=llmemory.WeakRefPtr)
+    if isinstance(hop.r_result, BaseWeakRefRepr):
+        return hop.r_result._weakref_create(hop, v_inst)
+    else:
+        # low-level <PtrRepr * WeakRef>
+        assert hop.rtyper.getconfig().translation.rweakref
+        return hop.genop('weakref_create', [v_inst],
+                         resulttype=llmemory.WeakRefPtr)
 
 @typer_for(llmemory.weakref_deref)
 def rtype_weakref_deref(hop):
+    assert hop.rtyper.getconfig().translation.rweakref
     c_ptrtype, v_wref = hop.inputargs(lltype.Void, hop.args_r[1])
     assert v_wref.concretetype == llmemory.WeakRefPtr
     hop.exception_cannot_occur()
@@ -748,6 +757,7 @@
 
 @typer_for(llmemory.cast_ptr_to_weakrefptr)
 def rtype_cast_ptr_to_weakrefptr(hop):
+    assert hop.rtyper.getconfig().translation.rweakref
     vlist = hop.inputargs(hop.args_r[0])
     hop.exception_cannot_occur()
     return hop.genop('cast_ptr_to_weakrefptr', vlist,
@@ -755,6 +765,7 @@
 
 @typer_for(llmemory.cast_weakrefptr_to_ptr)
 def rtype_cast_weakrefptr_to_ptr(hop):
+    assert hop.rtyper.getconfig().translation.rweakref
     c_ptrtype, v_wref = hop.inputargs(lltype.Void, hop.args_r[1])
     assert v_wref.concretetype == llmemory.WeakRefPtr
     hop.exception_cannot_occur()
diff --git a/rpython/rtyper/rweakref.py b/rpython/rtyper/rweakref.py
--- a/rpython/rtyper/rweakref.py
+++ b/rpython/rtyper/rweakref.py
@@ -11,25 +11,22 @@
 
 class __extend__(annmodel.SomeWeakRef):
     def rtyper_makerepr(self, rtyper):
-        return WeakRefRepr(rtyper)
+        if rtyper.getconfig().translation.rweakref:
+            return WeakRefRepr(rtyper)
+        else:
+            return EmulatedWeakRefRepr(rtyper)
 
     def rtyper_makekey(self):
         return self.__class__,
 
-class WeakRefRepr(Repr):
-    lowleveltype = llmemory.WeakRefPtr
-    dead_wref = llmemory.dead_wref
-    null_wref = lltype.nullptr(llmemory.WeakRef)
 
+class BaseWeakRefRepr(Repr):
     def __init__(self, rtyper):
         self.rtyper = rtyper
-        if not rtyper.getconfig().translation.rweakref:
-            raise TyperError("RPython-level weakrefs are not supported by "
-                             "this backend or GC policy")
 
     def convert_const(self, value):
         if value is None:
-            return self.null_wref
+            return lltype.nullptr(self.lowleveltype.TO)
 
         assert isinstance(value, weakref.ReferenceType)
         instance = value()
@@ -39,8 +36,7 @@
         else:
             repr = self.rtyper.bindingrepr(Constant(instance))
             llinstance = repr.convert_const(instance)
-            return self._weakref_create(llinstance)
-
+            return self.do_weakref_create(llinstance)
 
     def rtype_simple_call(self, hop):
         v_wref, = hop.inputargs(self)
@@ -48,8 +44,53 @@
         if hop.r_result.lowleveltype is lltype.Void: # known-to-be-dead weakref
             return hop.inputconst(lltype.Void, None)
         else:
-            return hop.genop('weakref_deref', [v_wref],
-                             resulttype=hop.r_result)
+            assert v_wref.concretetype == self.lowleveltype
+            return self._weakref_deref(hop, v_wref)
 
-    def _weakref_create(self, llinstance):
+
+class WeakRefRepr(BaseWeakRefRepr):
+    lowleveltype = llmemory.WeakRefPtr
+    dead_wref = llmemory.dead_wref
+
+    def do_weakref_create(self, llinstance):
         return llmemory.weakref_create(llinstance)
+
+    def _weakref_create(self, hop, v_inst):
+        return hop.genop('weakref_create', [v_inst],
+                         resulttype=llmemory.WeakRefPtr)
+
+    def _weakref_deref(self, hop, v_wref):
+        return hop.genop('weakref_deref', [v_wref],
+                         resulttype=hop.r_result)
+
+
+class EmulatedWeakRefRepr(BaseWeakRefRepr):
+    """For the case rweakref=False, we emulate RPython-level weakrefs
+    with regular strong references (but not low-level weakrefs).
+    """
+    lowleveltype = lltype.Ptr(lltype.GcStruct('EmulatedWeakRef',
+                                              ('ref', llmemory.GCREF)))
+    dead_wref = lltype.malloc(lowleveltype.TO, immortal=True, zero=True)
+
+    def do_weakref_create(self, llinstance):
+        p = lltype.malloc(self.lowleveltype.TO, immortal=True)
+        p.ref = lltype.cast_opaque_ptr(llmemory.GCREF, llinstance)
+        return p
+
+    def _weakref_create(self, hop, v_inst):
+        c_type = hop.inputconst(lltype.Void, self.lowleveltype.TO)
+        c_flags = hop.inputconst(lltype.Void, {'flavor': 'gc'})
+        v_ptr = hop.genop('malloc', [c_type, c_flags],
+                          resulttype=self.lowleveltype)
+        v_gcref = hop.genop('cast_opaque_ptr', [v_inst],
+                            resulttype=llmemory.GCREF)
+        c_ref = hop.inputconst(lltype.Void, 'ref')
+        hop.genop('setfield', [v_ptr, c_ref, v_gcref])
+        return v_ptr
+
+    def _weakref_deref(self, hop, v_wref):
+        c_ref = hop.inputconst(lltype.Void, 'ref')
+        v_gcref = hop.genop('getfield', [v_wref, c_ref],
+                            resulttype=llmemory.GCREF)
+        return hop.genop('cast_opaque_ptr', [v_gcref],
+                         resulttype=hop.r_result)
diff --git a/rpython/rtyper/test/test_rweakref.py b/rpython/rtyper/test/test_rweakref.py
--- a/rpython/rtyper/test/test_rweakref.py
+++ b/rpython/rtyper/test/test_rweakref.py
@@ -138,3 +138,22 @@
 
         res = self.interpret(f, [])
         assert res == lltype.nullptr(S)
+
+
+class TestRWeakrefDisabled(BaseRtypingTest):
+    def test_no_real_weakref(self):
+        class A:
+            pass
+        a1 = A()
+        mylist = [weakref.ref(a1), None]
+        def g():
+            a2 = A()
+            return weakref.ref(a2)
+        def fn(i):
+            w = g()
+            rgc.collect()
+            assert w() is not None
+            return mylist[i] is None
+
+        assert self.interpret(fn, [0], rweakref=False) is False
+        assert self.interpret(fn, [1], rweakref=False) is True


More information about the pypy-commit mailing list