Author: Carl Friedrich Bolz <cfb...@gmx.de>
Branch: 
Changeset: r86909:aab338e52409
Date: 2016-09-06 16:50 +0200
http://bitbucket.org/pypy/pypy/changeset/aab338e52409/

Log:    improve the trace of import statements to not contain calls

        (needed slightly awkward code)

diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -259,10 +259,8 @@
         raise oefmt(space.w_ValueError, "Empty module name")
     w = space.wrap
 
-    if w_fromlist is not None and space.is_true(w_fromlist):
-        fromlist_w = space.fixedview(w_fromlist)
-    else:
-        fromlist_w = None
+    if w_fromlist is not None and not space.is_true(w_fromlist):
+        w_fromlist = None
 
     rel_modulename = None
     if (level != 0 and w_globals is not None and
@@ -284,19 +282,19 @@
                     w_mod = None
                 else:
                     w_mod = absolute_import(space, rel_modulename, rel_level,
-                                            fromlist_w, tentative=True)
+                                            w_fromlist, tentative=True)
             else:
                 w_mod = absolute_import(space, rel_modulename, rel_level,
-                                        fromlist_w, tentative=False)
+                                        w_fromlist, tentative=False)
             if w_mod is not None:
                 return w_mod
 
-    w_mod = absolute_import(space, modulename, 0, fromlist_w, tentative=0)
+    w_mod = absolute_import(space, modulename, 0, w_fromlist, tentative=0)
     if rel_modulename is not None:
         space.setitem(space.sys.get('modules'), w(rel_modulename), 
space.w_None)
     return w_mod
 
-def absolute_import(space, modulename, baselevel, fromlist_w, tentative):
+def absolute_import(space, modulename, baselevel, w_fromlist, tentative):
     # Short path: check in sys.modules, but only if there is no conflict
     # on the import lock.  In the situation of 'import' statements
     # inside tight loops, this should be true, and absolute_import_try()
@@ -304,25 +302,25 @@
     # if the import lock is currently held by another thread, then we
     # have to wait, and so shouldn't use the fast path.
     if not getimportlock(space).lock_held_by_someone_else():
-        w_mod = absolute_import_try(space, modulename, baselevel, fromlist_w)
+        w_mod = absolute_import_try(space, modulename, baselevel, w_fromlist)
         if w_mod is not None and not space.is_w(w_mod, space.w_None):
             return w_mod
     return absolute_import_with_lock(space, modulename, baselevel,
-                                     fromlist_w, tentative)
+                                     w_fromlist, tentative)
 
 @jit.dont_look_inside
 def absolute_import_with_lock(space, modulename, baselevel,
-                              fromlist_w, tentative):
+                              w_fromlist, tentative):
     lock = getimportlock(space)
     lock.acquire_lock()
     try:
         return _absolute_import(space, modulename, baselevel,
-                                fromlist_w, tentative)
+                                w_fromlist, tentative)
     finally:
         lock.release_lock(silent_after_fork=True)
 
 @jit.unroll_safe
-def absolute_import_try(space, modulename, baselevel, fromlist_w):
+def absolute_import_try(space, modulename, baselevel, w_fromlist):
     """ Only look up sys.modules, not actually try to load anything
     """
     w_path = None
@@ -330,7 +328,7 @@
     if '.' not in modulename:
         w_mod = check_sys_modules_w(space, modulename)
         first = w_mod
-        if fromlist_w is not None and w_mod is not None:
+        if w_fromlist is not None and w_mod is not None:
             w_path = try_getattr(space, w_mod, space.wrap('__path__'))
     else:
         level = 0
@@ -345,28 +343,36 @@
                 return None
             if level == baselevel:
                 first = w_mod
-            if fromlist_w is not None:
+            if w_fromlist is not None:
                 w_path = try_getattr(space, w_mod, space.wrap('__path__'))
             level += 1
-    if fromlist_w is not None:
+    if w_fromlist is not None:
+        # bit artificial code but important to not just unwrap w_fromlist
+        # to get a better trace. if it is unwrapped, the immutability of the
+        # tuple is lost
         if w_path is not None:
-            if len(fromlist_w) == 1 and space.eq_w(fromlist_w[0],
-                                                   space.wrap('*')):
+            length = space.len_w(w_fromlist)
+            if length == 1 and space.eq_w(
+                    space.getitem(w_fromlist, space.wrap(0)),
+                    space.wrap('*')):
                 w_all = try_getattr(space, w_mod, space.wrap('__all__'))
                 if w_all is not None:
-                    fromlist_w = space.fixedview(w_all)
+                    w_fromlist = w_all
                 else:
-                    fromlist_w = []
+                    w_fromlist = None
                     # "from x import *" with x already imported and no 
x.__all__
                     # always succeeds without doing more imports.  It will
                     # just copy everything from x.__dict__ as it is now.
-            for w_name in fromlist_w:
-                if try_getattr(space, w_mod, w_name) is None:
-                    return None
+
+            if w_fromlist is not None:
+                for i in range(length):
+                    w_name = space.getitem(w_fromlist, space.wrap(i))
+                    if try_getattr(space, w_mod, w_name) is None:
+                        return None
         return w_mod
     return first
 
-def _absolute_import(space, modulename, baselevel, fromlist_w, tentative):
+def _absolute_import(space, modulename, baselevel, w_fromlist, tentative):
     w = space.wrap
 
     if '/' in modulename or '\\' in modulename:
@@ -394,18 +400,23 @@
         w_path = try_getattr(space, w_mod, w('__path__'))
         level += 1
 
-    if fromlist_w is not None:
+    if w_fromlist is not None:
         if w_path is not None:
-            if len(fromlist_w) == 1 and space.eq_w(fromlist_w[0],w('*')):
+            length = space.len_w(w_fromlist)
+            if length == 1 and space.eq_w(
+                    space.getitem(w_fromlist, space.wrap(0)),
+                    space.wrap('*')):
                 w_all = try_getattr(space, w_mod, w('__all__'))
                 if w_all is not None:
-                    fromlist_w = space.fixedview(w_all)
+                    w_fromlist = w_all
                 else:
-                    fromlist_w = []
-            for w_name in fromlist_w:
-                if try_getattr(space, w_mod, w_name) is None:
-                    load_part(space, w_path, prefix, space.str0_w(w_name),
-                              w_mod, tentative=1)
+                    w_fromlist = None
+            if w_fromlist is not None:
+                for i in range(length):
+                    w_name = space.getitem(w_fromlist, space.wrap(i))
+                    if try_getattr(space, w_mod, w_name) is None:
+                        load_part(space, w_path, prefix, space.str0_w(w_name),
+                                  w_mod, tentative=1)
         return w_mod
     else:
         return first
diff --git a/pypy/module/pypyjit/test_pypy_c/test_import.py 
b/pypy/module/pypyjit/test_pypy_c/test_import.py
--- a/pypy/module/pypyjit/test_pypy_c/test_import.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_import.py
@@ -38,3 +38,27 @@
         # call_may_force(absolute_import_with_lock).
         for opname in log.opnames(loop.allops(opcode="IMPORT_NAME")):
             assert 'call' not in opname    # no call-like opcode
+
+    def test_import_fast_path(self, tmpdir):
+        print tmpdir
+        pkg = tmpdir.join('mypkg').ensure(dir=True)
+        subdir = pkg.join("sub").ensure(dir=True)
+        pkg.join('__init__.py').write("")
+        subdir.join('__init__.py').write("")
+        subdir.join('mod.py').write(str(py.code.Source("""
+            def do_the_import():
+                import sys
+        """)))
+        def main(path, n):
+            def do_the_import():
+                from mypkg.sub import mod
+            import sys
+            sys.path.append(path)
+            for i in range(n):
+                do_the_import()
+        #
+        log = self.run(main, [str(tmpdir), 300])
+        loop, = log.loops_by_filename(self.filepath)
+        # check that no string compares and other calls are there
+        for opname in log.opnames(loop.allops(opcode="IMPORT_NAME")):
+            assert 'call' not in opname    # no call-like opcode
diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py
--- a/pypy/objspace/std/celldict.py
+++ b/pypy/objspace/std/celldict.py
@@ -64,6 +64,8 @@
 
     def setitem_str(self, w_dict, key, w_value):
         cell = self.getdictvalue_no_unwrapping(w_dict, key)
+        #if (key == '__package__' or key == "__path__") and cell is not None 
and w_value is not cell:
+        #    print "WARNING", key, w_value, cell, self
         return self._setitem_str_cell_known(cell, w_dict, key, w_value)
 
     def _setitem_str_cell_known(self, cell, w_dict, key, w_value):
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to