[pypy-commit] pypy cffi-1.0: @elidable needs a bit of care: it cannot be used on functions that

arigo noreply at buildbot.pypy.org
Fri May 8 21:24:33 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r77234:b67dbf9a0ed8
Date: 2015-05-08 20:24 +0200
http://bitbucket.org/pypy/pypy/changeset/b67dbf9a0ed8/

Log:	@elidable needs a bit of care: it cannot be used on functions that
	indirectly cause external function calls or GIL releases. I hope
	that these tweaks are enough.

diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py
--- a/pypy/module/_cffi_backend/ffi_obj.py
+++ b/pypy/module/_cffi_backend/ffi_obj.py
@@ -46,11 +46,24 @@
         self.w_FFIError = get_ffi_error(space)
         self.included_libs = []        # list of W_LibObject's included here
 
-    @jit.elidable
-    def parse_string_to_type(self, string, flags):
-        try:
-            x = self.types_dict[string]
-        except KeyError:
+    @jit.elidable_promote()
+    def get_string_to_type(self, string, consider_fn_as_fnptr):
+        x = self.types_dict[string]     # KeyError if not found
+        if isinstance(x, W_CType):
+            return x
+        elif consider_fn_as_fnptr:
+            return realize_c_type.unwrap_fn_as_fnptr(x)
+        else:
+            return realize_c_type.unexpected_fn_type(self, x)
+
+    @jit.dont_look_inside
+    def parse_string_to_type(self, string, consider_fn_as_fnptr):
+        # This cannot be made @elidable because it calls general space
+        # functions (indirectly, e.g. via the new_xxx_type() functions).
+        # The get_string_to_type() function above is elidable, and we
+        # hope that in almost all cases, get_string_to_type() has already
+        # found an answer.
+        if string not in self.types_dict:
             info = self.ctxobj.info
             index = parse_c_type.parse_c_type(info, string)
             if index < 0:
@@ -62,20 +75,19 @@
             x = realize_c_type.realize_c_type_or_func(
                 self, self.ctxobj.info.c_output, index)
             self.types_dict[string] = x
-
-        if isinstance(x, W_CType):
-            return x
-        elif flags & CONSIDER_FN_AS_FNPTR:
-            return realize_c_type.unwrap_fn_as_fnptr(x)
-        else:
-            return realize_c_type.unexpected_fn_type(self, x)
+        return self.get_string_to_type(string, consider_fn_as_fnptr)
 
     def ffi_type(self, w_x, accept):
         space = self.space
         if (accept & ACCEPT_STRING) and space.isinstance_w(w_x, space.w_str):
-            self = jit.promote(self)
-            return self.parse_string_to_type(space.str_w(w_x),
-                                             accept & CONSIDER_FN_AS_FNPTR)
+            string = space.str_w(w_x)
+            consider_fn_as_fnptr = (accept & CONSIDER_FN_AS_FNPTR) != 0
+            if jit.isconstant(string):
+                try:
+                    return self.get_string_to_type(string, consider_fn_as_fnptr)
+                except KeyError:
+                    pass
+            return self.parse_string_to_type(string, consider_fn_as_fnptr)
         if (accept & ACCEPT_CTYPE) and isinstance(w_x, W_CType):
             return w_x
         if (accept & ACCEPT_CDATA) and isinstance(w_x, W_CData):
diff --git a/pypy/module/_cffi_backend/lib_obj.py b/pypy/module/_cffi_backend/lib_obj.py
--- a/pypy/module/_cffi_backend/lib_obj.py
+++ b/pypy/module/_cffi_backend/lib_obj.py
@@ -40,17 +40,23 @@
 
     @jit.elidable_promote()
     def _get_attr_elidable(self, attr):
-        try:
-            w_result = self.dict_w[attr]
-        except KeyError:
-            index = parse_c_type.search_in_globals(self.ctx, attr)
-            if index < 0:
-                for lib1 in self.ffi.included_libs:
+        return self.dict_w[attr]     # KeyError if not found
+
+    @jit.dont_look_inside
+    def _build_attr(self, attr):
+        index = parse_c_type.search_in_globals(self.ctx, attr)
+        if index < 0:
+            for lib1 in self.ffi.included_libs:
+                try:
                     w_result = lib1._get_attr_elidable(attr)
-                    if w_result is not None:
-                        return w_result
-                return None     # no active caching, but still @elidable
-
+                except KeyError:
+                    w_result = lib1._build_attr(attr)
+                    if w_result is None:
+                        continue
+                break           # found, break out of this loop
+            else:
+                return None     # not found at all
+        else:
             space = self.space
             g = self.ctx.c_globals[index]
             op = getop(g.c_type_op)
@@ -101,17 +107,21 @@
                 raise oefmt(space.w_NotImplementedError,
                             "in lib_build_attr: op=%d", op)
 
-            self.dict_w[attr] = w_result
+        assert w_result is not None
+        self.dict_w[attr] = w_result
         return w_result
 
     def _get_attr(self, w_attr):
         attr = self.space.str_w(w_attr)
-        w_value = self._get_attr_elidable(attr)
-        if w_value is None:
-            raise oefmt(self.space.w_AttributeError,
-                        "cffi lib '%s' has no function,"
-                        " global variable or constant named '%s'",
-                        self.libname, attr)
+        try:
+            w_value = self._get_attr_elidable(attr)
+        except KeyError:
+            w_value = self._build_attr(attr)
+            if w_value is None:
+                raise oefmt(self.space.w_AttributeError,
+                            "cffi lib '%s' has no function,"
+                            " global variable or constant named '%s'",
+                            self.libname, attr)
         return w_value
 
     def descr_getattribute(self, w_attr):
diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -598,7 +598,8 @@
         fargs.append(w_farg)
     return _new_function_type(space, fargs, w_fresult, bool(ellipsis))
 
- at jit.elidable
+# can't use @jit.elidable here, because it might call back to random
+# space functions via force_lazy_struct()
 def _new_function_type(space, fargs, w_fresult, ellipsis=False):
     from pypy.module._cffi_backend import ctypefunc
     #


More information about the pypy-commit mailing list