Author: Carl Friedrich Bolz <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit