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

Reply via email to