Author: Anton Gulenko <[email protected]>
Branch: storage
Changeset: r910:9a0c4bf44ab6
Date: 2014-07-14 18:42 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/9a0c4bf44ab6/

Log:    Improved crash report when running in headless mode. Refactored
        flushCache primitive to walk the GC roots with less memory overhead.
        Not allocating huge lists containing all objects, instead walking
        recursively.

diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py
--- a/spyvm/interpreter.py
+++ b/spyvm/interpreter.py
@@ -224,7 +224,7 @@
         s_frame.push(w_receiver)
         s_frame.push_all(list(w_arguments))
         return s_frame
-
+        
     # ============== Methods for tracing, printing and debugging ==============
 
     def activate_trace(self, trace_depth=0):
@@ -585,7 +585,7 @@
             w_method = receiverclassshadow.lookup(w_selector)
         except MethodNotFound:
             return self._doesNotUnderstand(w_selector, argcount, interp, 
receiver)
-
+        
         code = w_method.primitive()
         if code:
             if w_arguments:
@@ -615,7 +615,7 @@
         s_class = receiver.class_shadow(self.space)
         w_method = s_class.lookup(w_special_selector)
         s_frame = w_method.create_frame(interp.space, receiver, w_args)
-
+        
         # 
######################################################################
         if interp.is_tracing():
             interp.print_padded('-> %s %s' % (special_selector, 
s_frame.short_str()))
@@ -635,13 +635,15 @@
         self.pop() # The receiver, already known.
 
         try:
+            if interp.space.headless.is_set():
+                primitives.exitFromHeadlessExecution(self, 
"doesNotUnderstand:", w_message)
             return self._sendSpecialSelector(interp, receiver, 
"doesNotUnderstand", [w_message])
         except MethodNotFound:
             from spyvm.shadow import ClassShadow
             s_class = receiver.class_shadow(self.space)
             assert isinstance(s_class, ClassShadow)
-            print "Missing doesNotUnderstand in hierarchy of %s" % 
s_class.getname()
-            raise
+            from spyvm import error
+            raise error.Exit("Missing doesNotUnderstand in hierarchy of %s" % 
s_class.getname())
 
     def _mustBeBoolean(self, interp, receiver):
         return self._sendSpecialSelector(interp, receiver, "mustBeBoolean")
@@ -665,11 +667,11 @@
     def _return(self, return_value, interp, local_return=False):
         # unfortunately, this assert is not true for some tests. TODO fix this.
         # assert self._stack_ptr == self.tempsize()
-
+        
         # ##################################################################
         if interp.is_tracing():
             interp.print_padded('<- ' + return_value.as_repr_string())
-
+        
         if self.home_is_self() or local_return:
             # a local return just needs to go up the stack once. there
             # it will find the sender as a local, and we don't have to
diff --git a/spyvm/primitives.py b/spyvm/primitives.py
--- a/spyvm/primitives.py
+++ b/spyvm/primitives.py
@@ -6,7 +6,7 @@
 from spyvm.error import PrimitiveFailedError, PrimitiveNotYetWrittenError
 from spyvm import wrapper
 
-from rpython.rlib import rarithmetic, rfloat, unroll, jit
+from rpython.rlib import rarithmetic, rfloat, unroll, jit, objectmodel
 
 def assert_class(interp, w_obj, w_class):
     if not w_obj.getclass(interp.space).is_same_object(w_class):
@@ -375,30 +375,34 @@
         return w_obj.as_string()
     return w_obj.as_repr_string()
 
+def exitFromHeadlessExecution(s_frame, selector="", w_message=None):
+    if not objectmodel.we_are_translated():
+        import pdb; pdb.set_trace()
+    print "== Receiver: %s" % s_frame.w_receiver().as_repr_string()
+    if isinstance(w_message, model.W_PointersObject):
+        fields = w_message.fetch_all(s_frame.space)
+        if len(fields) >= 1:
+            print "== Selector: %s" % get_string(fields[0])
+        if len(fields) >= 2:
+            w_args = fields[1]
+            if isinstance(w_args, model.W_PointersObject):
+                arg_strings = [ get_string(w_arg) for w_arg in 
w_args.fetch_all(s_frame.space) ]
+                if len(arg_strings) > 0:
+                    print "== Arguments: %s" % ', '.join(arg_strings)
+    print "== Smalltalk Stack:%s" % s_frame.print_stack()
+    if selector == "":
+        selector = s_frame.w_method().lookup_selector
+    raise error.Exit("Unhandled %s in headless mode." % selector)
+    
 @expose_primitive(FAIL)
 def func(interp, s_frame, argcount):
-    if interp.space.headless.is_set() and s_frame.w_method().lookup_selector 
== 'doesNotUnderstand:':
-        print "== Error message: %s" % get_string(s_frame.peek(1))
-        print "== Receiver: %s" % s_frame.w_receiver().as_repr_string()
-        w_arguments = s_frame.w_arguments()
-        if len(w_arguments) >= 1:
-            w_message = w_arguments[0]
-            if isinstance(w_message, model.W_PointersObject):
-                fields = w_message.fetch_all(interp.space)
-                if len(fields) >= 1:
-                    print "== Selector: %s" % get_string(fields[0])
-                if len(fields) >= 2:
-                    w_args = fields[0]
-                    if isinstance(w_args, model.W_PointersObject):
-                        arg_strings = [ get_string(w_arg) for w_arg in 
w_args.fetch_all(interp.space) ]
-                        print "== Arguments: %s" % ', '.join(arg_strings)
-            else:
-                print "== Message: %s" % w_message
-        print "== VM Stack:%s" % s_frame.print_stack()
-        w_stack = s_frame.peek(0)
-        if isinstance(w_stack, model.W_BytesObject):
-            print "== Squeak stack:\n%s" % w_stack.as_string()
-        raise error.Exit("Unhandled doesNotUnderstand:")
+    if interp.space.headless.is_set():
+        w_message = None
+        if s_frame.w_method().lookup_selector == 'doesNotUnderstand:':
+            w_arguments = s_frame.w_arguments()
+            if len(w_arguments) >= 1:
+                w_message = w_arguments[0]
+        exitFromHeadlessExecution(s_frame, w_message=w_message)
     raise PrimitiveFailedError()
 
 # ___________________________________________________________________________
@@ -725,6 +729,9 @@
 
 @expose_primitive(BE_DISPLAY, unwrap_spec=[object])
 def func(interp, s_frame, w_rcvr):
+    if interp.space.headless.is_set():
+        exitFromHeadlessExecution(s_frame)
+    
     if not isinstance(w_rcvr, model.W_PointersObject) or w_rcvr.size() < 4:
         raise PrimitiveFailedError
     # the fields required are bits (a pointer to a Bitmap), width, height, 
depth
@@ -857,7 +864,6 @@
 
 @expose_primitive(EXIT_TO_DEBUGGER, unwrap_spec=[object])
 def func(interp, s_frame, w_rcvr):
-    from rpython.rlib import objectmodel
     if not objectmodel.we_are_translated():
         import pdb; pdb.set_trace()
     raise PrimitiveNotYetWrittenError()
@@ -930,36 +936,38 @@
         w_class.as_class_get_shadow(interp.space).flush_method_caches()
     return w_rcvr
 
[email protected](0)
+def walk_gc_references(func, gcrefs):
+    from rpython.rlib import rgc
+    for gcref in gcrefs:
+        if gcref and not rgc.get_gcflag_extra(gcref):
+            try:
+                rgc.toggle_gcflag_extra(gcref)
+                func(gcref)
+                walk_gc_references(func, rgc.get_rpy_referents(gcref))
+            finally:
+                rgc.toggle_gcflag_extra(gcref)
 
[email protected](0)
+def walk_gc_objects(func):
+    from rpython.rlib import rgc
+    walk_gc_references(func, rgc.get_rpy_roots())
+
[email protected](0, 1)
+def walk_gc_objects_of_type(type, func):
+    from rpython.rlib import rgc
+    def check_type(gcref):
+        w_obj = rgc.try_cast_gcref_to_instance(type, gcref)
+        if w_obj:
+            func(w_obj)
+    walk_gc_objects(check_type)
+    
 if not stm_enabled():
-    # XXX: We don't have a global symbol cache. Instead, we get all
-    # method dictionary shadows (those exists for all methodDicts that
-    # have been modified) and flush them
+    # XXX: We don't have a global symbol cache. Instead, we walk all
+    # MethodDictionaryShadow objects and flush them.
     @expose_primitive(SYMBOL_FLUSH_CACHE, unwrap_spec=[object])
     def func(interp, s_frame, w_rcvr):
-        dicts_s = []
-        from rpython.rlib import rgc
-
-        roots = [gcref for gcref in rgc.get_rpy_roots() if gcref]
-        pending = roots[:]
-        while pending:
-            gcref = pending.pop()
-            if not rgc.get_gcflag_extra(gcref):
-                rgc.toggle_gcflag_extra(gcref)
-                w_obj = 
rgc.try_cast_gcref_to_instance(shadow.MethodDictionaryShadow, gcref)
-                if w_obj is not None:
-                    dicts_s.append(w_obj)
-                pending.extend(rgc.get_rpy_referents(gcref))
-
-        while roots:
-            gcref = roots.pop()
-            if rgc.get_gcflag_extra(gcref):
-                rgc.toggle_gcflag_extra(gcref)
-                roots.extend(rgc.get_rpy_referents(gcref))
-
-        for s_dict in dicts_s:
-            if s_dict.invalid:
-                s_dict.sync_method_cache()
+        walk_gc_objects_of_type(shadow.MethodDictionaryShadow, lambda s_dict: 
s_dict.flush_method_cache())
         return w_rcvr
 
 # ___________________________________________________________________________
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to