Author: Armin Rigo <[email protected]>
Branch: reverse-debugger
Changeset: r85541:d0a272e97616
Date: 2016-07-04 18:12 +0200
http://bitbucket.org/pypy/pypy/changeset/d0a272e97616/
Log: Add space._side_effects_ok(). See doc. Still not working.
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
@@ -1199,7 +1199,7 @@
def visit_RevDBMetaVar(self, node):
if self.space.config.translation.reverse_debugger:
from pypy.interpreter.reverse_debugging import dbstate
- if dbstate.extend_syntax_with_dollar_num:
+ if not dbstate.standard_code:
self.emit_op_arg(ops.LOAD_REVDB_VAR, node.metavar)
return
self.error("$NUM is only valid in the reverse-debugger", node)
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
@@ -944,10 +944,11 @@
from pypy.interpreter.reverse_debugging import dbstate, setup_revdb
self.space.config.translation.reverse_debugger = True
setup_revdb(self.space)
- dbstate.extend_syntax_with_dollar_num = True
+ dbstate.standard_code = False
dbstate.metavars = [self.space.wrap(6)]
self.simple_test("x = 7*$0", "x", 42)
- dbstate.extend_syntax_with_dollar_num = False
+ dbstate.standard_code = True
+ self.error_test("x = 7*$0", SyntaxError)
class AppTestCompiler:
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -811,7 +811,8 @@
w_s1 = self.interned_strings.get(s)
if w_s1 is None:
w_s1 = w_s
- self.interned_strings.set(s, w_s1)
+ if self._side_effects_ok():
+ self.interned_strings.set(s, w_s1)
return w_s1
def new_interned_str(self, s):
@@ -820,9 +821,30 @@
w_s1 = self.interned_strings.get(s)
if w_s1 is None:
w_s1 = self.wrap(s)
- self.interned_strings.set(s, w_s1)
+ if self._side_effects_ok():
+ self.interned_strings.set(s, w_s1)
return w_s1
+ def _side_effects_ok(self):
+ # For the reverse debugger: we run compiled watchpoint
+ # expressions in a fast way that will crash if they have
+ # side-effects. The obvious Python code with side-effects is
+ # documented "don't do that"; but some non-obvious side
+ # effects are also common, like interning strings (from
+ # unmarshalling the code object containing the watchpoint
+ # expression) to the two attribute caches in mapdict.py and
+ # typeobject.py. For now, we have to identify such places
+ # that are not acceptable for "reasonable" read-only
+ # watchpoint expressions, and write:
+ #
+ # if not space._side_effects_ok():
+ # don't cache.
+ #
+ if self.config.translation.reverse_debugger:
+ from pypy.interpreter.reverse_debugging import dbstate
+ return dbstate.standard_code
+ return True
+
def is_interned_str(self, s):
# interface for marshal_impl
if not we_are_translated():
diff --git a/pypy/interpreter/reverse_debugging.py
b/pypy/interpreter/reverse_debugging.py
--- a/pypy/interpreter/reverse_debugging.py
+++ b/pypy/interpreter/reverse_debugging.py
@@ -11,7 +11,6 @@
class DBState:
- extend_syntax_with_dollar_num = False
standard_code = True
breakpoint_stack_id = 0
breakpoint_funcnames = None
@@ -258,12 +257,8 @@
def compile(source, mode):
space = dbstate.space
compiler = space.createcompiler()
- dbstate.extend_syntax_with_dollar_num = True
- try:
- code = compiler.compile(source, '<revdb>', mode, 0,
- hidden_applevel=True)
- finally:
- dbstate.extend_syntax_with_dollar_num = False
+ code = compiler.compile(source, '<revdb>', mode, 0,
+ hidden_applevel=True)
return code
@@ -526,17 +521,16 @@
def command_compilewatch(cmd, expression):
space = dbstate.space
- try:
- code = compile(expression, 'eval')
- # Note: using version 0 to marshal watchpoints, in order to
- # avoid space.new_interned_str() on unmarshal. This is
- # forbidden because it comes with lasting side-effects.
- marshalled_code = space.str_w(interp_marshal.dumps(
- space, space.wrap(code), space.wrap(0)))
- except OperationError as e:
- revdb.send_watch(e.errorstr(space), ok_flag=0)
- else:
- revdb.send_watch(marshalled_code, ok_flag=1)
+ with non_standard_code:
+ try:
+ code = compile(expression, 'eval')
+ marshalled_code = space.str_w(interp_marshal.dumps(
+ space, space.wrap(code),
+ space.wrap(interp_marshal.Py_MARSHAL_VERSION)))
+ except OperationError as e:
+ revdb.send_watch(e.errorstr(space), ok_flag=0)
+ else:
+ revdb.send_watch(marshalled_code, ok_flag=1)
lambda_compilewatch = lambda: command_compilewatch
def command_checkwatch(cmd, marshalled_code):
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -94,12 +94,13 @@
cache.hits[name] = cache.hits.get(name, 0) + 1
return attr
attr = self._find_map_attr(name, index)
- cache.attrs[attr_hash] = self
- cache.names[attr_hash] = name
- cache.indexes[attr_hash] = index
- cache.cached_attrs[attr_hash] = attr
- if space.config.objspace.std.withmethodcachecounter:
- cache.misses[name] = cache.misses.get(name, 0) + 1
+ if space._side_effects_ok():
+ cache.attrs[attr_hash] = self
+ cache.names[attr_hash] = name
+ cache.indexes[attr_hash] = index
+ cache.cached_attrs[attr_hash] = attr
+ if space.config.objspace.std.withmethodcachecounter:
+ cache.misses[name] = cache.misses.get(name, 0) + 1
return attr
def _find_map_attr(self, name, index):
@@ -932,6 +933,8 @@
@jit.dont_look_inside
def _fill_cache(pycode, nameindex, map, version_tag, storageindex,
w_method=None):
+ if not pycode.space._side_effects_ok():
+ return
entry = pycode._mapdict_caches[nameindex]
if entry is INVALID_CACHE_ENTRY:
entry = CacheEntry()
diff --git a/pypy/objspace/std/test/test_dictmultiobject.py
b/pypy/objspace/std/test/test_dictmultiobject.py
--- a/pypy/objspace/std/test/test_dictmultiobject.py
+++ b/pypy/objspace/std/test/test_dictmultiobject.py
@@ -1100,6 +1100,9 @@
def fromcache(self, cls):
return cls(self)
+ def _side_effects_ok(self):
+ return True
+
w_StopIteration = StopIteration
w_None = None
w_NoneType = type(None, None)
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -248,7 +248,8 @@
# if it was not actually overriden in the class, we remember
this
# fact for the next time.
if w_descr is object_getattribute(self.space):
- self.uses_object_getattribute = True
+ if self.space._side_effects_ok():
+ self.uses_object_getattribute = True
else:
return w_descr
return None
@@ -275,10 +276,12 @@
self.lookup('__cmp__') or
self.lookup('__hash__') is not
default_hash)
if overrides_eq_cmp_or_hash:
- self.compares_by_identity_status = OVERRIDES_EQ_CMP_OR_HASH
+ result = OVERRIDES_EQ_CMP_OR_HASH
else:
- self.compares_by_identity_status = COMPARES_BY_IDENTITY
- return self.compares_by_identity_status == COMPARES_BY_IDENTITY
+ result = COMPARES_BY_IDENTITY
+ if self.space._side_effects_ok():
+ self.compares_by_identity_status = result
+ return result == COMPARES_BY_IDENTITY
def ready(self):
for w_base in self.bases_w:
@@ -454,11 +457,12 @@
# print "hit", self, name
return tup
tup = self._lookup_where_all_typeobjects(name)
- cache.versions[method_hash] = version_tag
- cache.names[method_hash] = name
- cache.lookup_where[method_hash] = tup
- if space.config.objspace.std.withmethodcachecounter:
- cache.misses[name] = cache.misses.get(name, 0) + 1
+ if space._side_effects_ok():
+ cache.versions[method_hash] = version_tag
+ cache.names[method_hash] = name
+ cache.lookup_where[method_hash] = tup
+ if space.config.objspace.std.withmethodcachecounter:
+ cache.misses[name] = cache.misses.get(name, 0) + 1
# print "miss", self, name
return tup
@@ -608,7 +612,7 @@
self)
w_newfunc = space.get(w_newdescr, self)
if (space.config.objspace.std.newshortcut and
- not we_are_jitted() and
+ not we_are_jitted() and space._side_effects_ok() and
isinstance(w_newtype, W_TypeObject)):
self.w_new_function = w_newfunc
w_newobject = space.call_obj_args(w_newfunc, self, __args__)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit