Author: Armin Rigo <[email protected]>
Branch:
Changeset: r64764:e953dfbc7f0a
Date: 2013-06-04 11:56 +0200
http://bitbucket.org/pypy/pypy/changeset/e953dfbc7f0a/
Log: merge the pull request #149, after a few extra fixes:
implement the -O and -OO flags, by Tyler Wade
Most importantly, this is done without generating .pyo files, but by
checking at runtime if we should run each assert or not. Similarly,
-OO is done by removing the docstrings from memory after we load the
.pyc files.
diff --git a/lib-python/2.7/opcode.py b/lib-python/2.7/opcode.py
--- a/lib-python/2.7/opcode.py
+++ b/lib-python/2.7/opcode.py
@@ -193,5 +193,6 @@
hasname.append(201)
def_op('CALL_METHOD', 202) # #args not including 'self'
def_op('BUILD_LIST_FROM_ARG', 203)
+jrel_op('JUMP_IF_NOT_DEBUG', 204) # Distance to target address
del def_op, name_op, jrel_op, jabs_op
diff --git a/lib_pypy/_pypy_irc_topic.py b/lib_pypy/_pypy_irc_topic.py
--- a/lib_pypy/_pypy_irc_topic.py
+++ b/lib_pypy/_pypy_irc_topic.py
@@ -1,4 +1,4 @@
-"""eclguba: flagnk naq frznagvpf bs clguba, fcrrq bs p, erfgevpgvbaf bs wnin
naq pbzcvyre reebe zrffntrf nf crargenoyr nf ZHZCF
+__doc__ = """eclguba: flagnk naq frznagvpf bs clguba, fcrrq bs p, erfgevpgvbaf
bs wnin naq pbzcvyre reebe zrffntrf nf crargenoyr nf ZHZCF
pglcrf unf n fcva bs 1/3
' ' vf n fcnpr gbb
Clguba 2.k rfg cerfdhr zbeg, ivir Clguba!
diff --git a/pypy/bin/pyinteractive.py b/pypy/bin/pyinteractive.py
--- a/pypy/bin/pyinteractive.py
+++ b/pypy/bin/pyinteractive.py
@@ -27,7 +27,8 @@
BoolOption("completer", "use readline commandline completer",
default=False, cmdline="-C"),
BoolOption("optimize",
- "dummy optimization flag for compatibility with CPython",
+ "skip assert statements and remove docstrings when importing
modules"
+ " (this is -OO in regular CPython)",
default=False, cmdline="-O"),
BoolOption("no_site_import", "do not 'import site' on initialization",
default=False, cmdline="-S"),
@@ -94,6 +95,17 @@
space.setitem(space.sys.w_dict, space.wrap('executable'),
space.wrap(argv[0]))
+ if interactiveconfig.optimize:
+ #change the optimize flag's value and set __debug__ to False
+ space.appexec([], """():
+ import sys
+ flags = list(sys.flags)
+ flags[6] = 2
+ sys.flags = type(sys.flags)(flags)
+ import __pypy__
+ __pypy__.set_debug(False)
+ """)
+
# call pypy_find_stdlib: the side-effect is that it sets sys.prefix and
# sys.exec_prefix
executable = argv[0]
diff --git a/pypy/doc/man/pypy.1.rst b/pypy/doc/man/pypy.1.rst
--- a/pypy/doc/man/pypy.1.rst
+++ b/pypy/doc/man/pypy.1.rst
@@ -16,7 +16,10 @@
Inspect interactively after running script.
-O
- Dummy optimization flag for compatibility with C Python.
+ Skip assert statements.
+
+-OO
+ Remove docstrings when importing modules in addition to -O.
-c *cmd*
Program passed in as CMD (terminates option list).
diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py
--- a/pypy/interpreter/app_main.py
+++ b/pypy/interpreter/app_main.py
@@ -2,8 +2,8 @@
# App-level version of py.py.
# See test/test_app_main.
-# Missing vs CPython: -d, -OO, -t, -v, -x, -3
-"""\
+# Missing vs CPython: -d, -t, -v, -x, -3
+USAGE1 = __doc__ = """\
Options and arguments (and corresponding environment variables):
-B : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x
-c cmd : program passed in as string (terminates option list)
@@ -12,7 +12,8 @@
-i : inspect interactively after running script; forces a prompt even
if stdin does not appear to be a terminal; also PYTHONINSPECT=x
-m mod : run library module as a script (terminates option list)
--O : dummy optimization flag for compatibility with CPython
+-O : skip assert statements
+-OO : remove docstrings when importing modules in addition to -O
-R : ignored (see http://bugs.python.org/issue14621)
-Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew
-s : don't add user site directory to sys.path; also PYTHONNOUSERSITE
@@ -27,7 +28,6 @@
PyPy options and arguments:
--info : print translation information about this PyPy executable
"""
-USAGE1 = __doc__
# Missing vs CPython: PYTHONHOME, PYTHONCASEOK
USAGE2 = """
Other environment variables:
@@ -470,6 +470,10 @@
sys.py3kwarning = bool(sys.flags.py3k_warning)
sys.dont_write_bytecode = bool(sys.flags.dont_write_bytecode)
+ if sys.flags.optimize >= 1:
+ import __pypy__
+ __pypy__.set_debug(False)
+
if sys.py3kwarning:
print >> sys.stderr, (
"Warning: pypy does not implement py3k warnings")
diff --git a/pypy/interpreter/astcompiler/assemble.py
b/pypy/interpreter/astcompiler/assemble.py
--- a/pypy/interpreter/astcompiler/assemble.py
+++ b/pypy/interpreter/astcompiler/assemble.py
@@ -245,6 +245,8 @@
if w_len is None:
w_len = space.len(self.w_consts)
space.setitem(self.w_consts, w_key, w_len)
+ if space.int_w(w_len) == 0:
+ self.scope.doc_removable = False
return space.int_w(w_len)
def _make_key(self, obj):
@@ -632,6 +634,7 @@
ops.JUMP_IF_FALSE_OR_POP : 0,
ops.POP_JUMP_IF_TRUE : -1,
ops.POP_JUMP_IF_FALSE : -1,
+ ops.JUMP_IF_NOT_DEBUG : 0,
ops.BUILD_LIST_FROM_ARG: 1,
}
diff --git a/pypy/interpreter/astcompiler/codegen.py
b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -254,6 +254,7 @@
start = 1
doc_expr.walkabout(self)
self.name_op("__doc__", ast.Store)
+ self.scope.doc_removable = True
for i in range(start, len(body)):
body[i].walkabout(self)
return True
@@ -371,6 +372,7 @@
def visit_Assert(self, asrt):
self.update_position(asrt.lineno)
end = self.new_block()
+ self.emit_jump(ops.JUMP_IF_NOT_DEBUG, end)
asrt.test.accept_jump_if(self, True, end)
self.emit_op_name(ops.LOAD_GLOBAL, self.names, "AssertionError")
if asrt.msg:
@@ -1207,7 +1209,10 @@
tree.walkabout(self)
def _get_code_flags(self):
- return 0
+ flags = 0
+ if self.scope.doc_removable:
+ flags |= consts.CO_KILL_DOCSTRING
+ return flags
class AbstractFunctionCodeGenerator(PythonCodeGenerator):
@@ -1234,6 +1239,8 @@
flags |= consts.CO_VARARGS
if scope.has_keywords_arg:
flags |= consts.CO_VARKEYWORDS
+ if scope.doc_removable:
+ flags |= consts.CO_KILL_DOCSTRING
if not self.cell_vars and not self.free_vars:
flags |= consts.CO_NOFREE
return PythonCodeGenerator._get_code_flags(self) | flags
@@ -1250,6 +1257,7 @@
doc_expr = None
if doc_expr is not None:
self.add_const(doc_expr.s)
+ self.scope.doc_removable = True
start = 1
else:
self.add_const(self.space.w_None)
@@ -1312,3 +1320,9 @@
self._handle_body(cls.body)
self.emit_op(ops.LOAD_LOCALS)
self.emit_op(ops.RETURN_VALUE)
+
+ def _get_code_flags(self):
+ flags = 0
+ if self.scope.doc_removable:
+ flags |= consts.CO_KILL_DOCSTRING
+ return PythonCodeGenerator._get_code_flags(self) | flags
diff --git a/pypy/interpreter/astcompiler/consts.py
b/pypy/interpreter/astcompiler/consts.py
--- a/pypy/interpreter/astcompiler/consts.py
+++ b/pypy/interpreter/astcompiler/consts.py
@@ -15,6 +15,8 @@
CO_FUTURE_WITH_STATEMENT = 0x8000
CO_FUTURE_PRINT_FUNCTION = 0x10000
CO_FUTURE_UNICODE_LITERALS = 0x20000
+#pypy specific:
+CO_KILL_DOCSTRING = 0x100000
PyCF_SOURCE_IS_UTF8 = 0x0100
PyCF_DONT_IMPLY_DEDENT = 0x0200
diff --git a/pypy/interpreter/astcompiler/symtable.py
b/pypy/interpreter/astcompiler/symtable.py
--- a/pypy/interpreter/astcompiler/symtable.py
+++ b/pypy/interpreter/astcompiler/symtable.py
@@ -42,6 +42,7 @@
self.has_free = False
self.child_has_free = False
self.nested = False
+ self.doc_removable = False
def lookup(self, name):
"""Find the scope of identifier 'name'."""
diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py
b/pypy/interpreter/astcompiler/test/test_compiler.py
--- a/pypy/interpreter/astcompiler/test/test_compiler.py
+++ b/pypy/interpreter/astcompiler/test/test_compiler.py
@@ -812,6 +812,58 @@
"""
self.simple_test(source, 'ok', 1)
+ def test_remove_docstring(self):
+ source = '"module_docstring"\n' + """if 1:
+ def f1():
+ 'docstring'
+ def f2():
+ 'docstring'
+ return 'docstring'
+ def f3():
+ 'foo'
+ return 'bar'
+ class C1():
+ 'docstring'
+ class C2():
+ __doc__ = 'docstring'
+ class C3():
+ field = 'not docstring'
+ class C4():
+ 'docstring'
+ field = 'docstring'
+ """
+ code_w = compile_with_astcompiler(source, 'exec', self.space)
+ code_w.remove_docstrings(self.space)
+ dict_w = self.space.newdict();
+ code_w.exec_code(self.space, dict_w, dict_w)
+
+ yield self.check, dict_w, "f1.__doc__", None
+ yield self.check, dict_w, "f2.__doc__", 'docstring'
+ yield self.check, dict_w, "f2()", 'docstring'
+ yield self.check, dict_w, "f3.__doc__", None
+ yield self.check, dict_w, "f3()", 'bar'
+ yield self.check, dict_w, "C1.__doc__", None
+ yield self.check, dict_w, "C2.__doc__", 'docstring'
+ yield self.check, dict_w, "C3.field", 'not docstring'
+ yield self.check, dict_w, "C4.field", 'docstring'
+ yield self.check, dict_w, "C4.__doc__", 'docstring'
+ yield self.check, dict_w, "C4.__doc__", 'docstring'
+ yield self.check, dict_w, "__doc__", None
+
+ def test_assert_skipping(self):
+ space = self.space
+ mod = space.getbuiltinmodule('__pypy__')
+ w_set_debug = space.getattr(mod, space.wrap('set_debug'))
+ space.call_function(w_set_debug, space.w_False)
+
+ source = """if 1:
+ assert False
+ """
+ try:
+ self.run(source)
+ finally:
+ space.call_function(w_set_debug, space.w_True)
+
class AppTestCompiler:
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -12,7 +12,7 @@
from pypy.interpreter.gateway import unwrap_spec
from pypy.interpreter.astcompiler.consts import (
CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS, CO_NESTED,
- CO_GENERATOR)
+ CO_GENERATOR, CO_KILL_DOCSTRING)
from pypy.tool.stdlib_opcode import opcodedesc, HAVE_ARGUMENT
from rpython.rlib.rarithmetic import intmask
from rpython.rlib.objectmodel import compute_hash
@@ -218,6 +218,13 @@
return w_first
return space.w_None
+ def remove_docstrings(self, space):
+ if self.co_flags & CO_KILL_DOCSTRING:
+ self.co_consts_w[0] = space.w_None
+ for w_co in self.co_consts_w:
+ if isinstance(w_co, PyCode):
+ w_co.remove_docstrings(space)
+
def _to_code(self):
"""For debugging only."""
consts = [None] * len(self.co_consts_w)
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -876,6 +876,11 @@
self.popvalue()
return next_instr
+ def JUMP_IF_NOT_DEBUG(self, jumpby, next_instr):
+ if not self.space.sys.debug:
+ next_instr += jumpby
+ return next_instr
+
def GET_ITER(self, oparg, next_instr):
w_iterable = self.popvalue()
w_iterator = self.space.iter(w_iterable)
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -58,6 +58,7 @@
'add_memory_pressure' : 'interp_magic.add_memory_pressure',
'newdict' : 'interp_dict.newdict',
'dictstrategy' : 'interp_dict.dictstrategy',
+ 'set_debug' : 'interp_magic.set_debug',
}
if sys.platform == 'win32':
interpleveldefs['get_console_cp'] = 'interp_magic.get_console_cp'
diff --git a/pypy/module/__pypy__/interp_magic.py
b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -101,6 +101,13 @@
def newlist_hint(space, sizehint):
return space.newlist_hint(sizehint)
+@unwrap_spec(debug=bool)
+def set_debug(space, debug):
+ space.sys.debug = debug
+ space.setitem(space.builtin.w_dict,
+ space.wrap('__debug__'),
+ space.wrap(debug))
+
@unwrap_spec(estimate=int)
def add_memory_pressure(estimate):
rgc.add_memory_pressure(estimate)
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
@@ -915,6 +915,13 @@
if not space.is_true(space.sys.get('dont_write_bytecode')):
write_compiled_module(space, code_w, cpathname, mode, mtime)
+ try:
+ optimize = space.sys.get_flag('optimize')
+ except Exception:
+ optimize = 0
+ if optimize >= 2:
+ code_w.remove_docstrings(space)
+
update_code_filenames(space, code_w, pathname)
exec_code_module(space, w_mod, code_w)
@@ -1009,6 +1016,13 @@
"Bad magic number in %s", cpathname)
#print "loading pyc file:", cpathname
code_w = read_compiled_module(space, cpathname, source)
+ try:
+ optimize = space.sys.get_flag('optimize')
+ except Exception:
+ optimize = 0
+ if optimize >= 2:
+ code_w.remove_docstrings(space)
+
exec_code_module(space, w_mod, code_w)
return w_mod
diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py
--- a/pypy/module/sys/__init__.py
+++ b/pypy/module/sys/__init__.py
@@ -7,7 +7,7 @@
class Module(MixedModule):
"""Sys Builtin Module. """
- _immutable_fields_ = ["defaultencoding?"]
+ _immutable_fields_ = ["defaultencoding?", "debug?"]
def __init__(self, space, w_name):
"""NOT_RPYTHON""" # because parent __init__ isn't
@@ -18,6 +18,7 @@
self.w_default_encoder = None
self.defaultencoding = "ascii"
self.filesystemencoding = None
+ self.debug = True
interpleveldefs = {
'__name__' : '(space.wrap("sys"))',
diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py
--- a/rpython/flowspace/flowcontext.py
+++ b/rpython/flowspace/flowcontext.py
@@ -800,6 +800,9 @@
self.popvalue()
return next_instr
+ def JUMP_IF_NOT_DEBUG(self, target, next_instr):
+ return next_instr
+
def GET_ITER(self, oparg, next_instr):
w_iterable = self.popvalue()
w_iterator = self.space.iter(w_iterable)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit