[pypy-svn] pypy lltrace: Support for generating trace events from inside the assembler

arigo commits-noreply at bitbucket.org
Tue Feb 22 14:59:54 CET 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: lltrace
Changeset: r42211:296023b39a57
Date: 2011-02-22 14:58 +0100
http://bitbucket.org/pypy/pypy/changeset/296023b39a57/

Log:	Support for generating trace events from inside the assembler
	produced by the JIT.

diff --git a/pypy/jit/backend/llsupport/trace.py b/pypy/jit/backend/llsupport/trace.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/backend/llsupport/trace.py
@@ -0,0 +1,17 @@
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.objectmodel import CDefinedIntSymbolic, we_are_translated
+
+
+# Calling this function adds an entry in the buffer maintained by
+# src/debug_lltrace.h.  Arguments: addr, newvalue, mark.
+trace_set = rffi.llexternal("_RPyTraceSet",
+                            [rffi.CCHARP, rffi.LONG, rffi.LONG],
+                            lltype.Void,
+                            _callable = lambda a, n, m: None,
+                            _nowrapper = True)
+
+_is_tracing = CDefinedIntSymbolic('RPY_IS_TRACING', default=0)
+addr_of_trace_set = CDefinedIntSymbolic('((long)&_RPyTraceSet)', default=0)
+
+def is_tracing():
+    return we_are_translated() and _is_tracing != 0

diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -39,6 +39,7 @@
 from pypy.jit.metainterp.history import ConstInt, BoxInt
 from pypy.jit.codewriter.effectinfo import EffectInfo
 from pypy.jit.codewriter import longlong
+from pypy.jit.backend.llsupport import trace
 
 # darwin requires the stack to be 16 bytes aligned on calls. Same for gcc 4.5.0,
 # better safe than sorry
@@ -1253,7 +1254,30 @@
         else:
             not_implemented("load_from_mem size = %d" % size)
 
-    def save_into_mem(self, dest_addr, value_loc, size_loc):
+    def generate_ll_trace(self, dest_addr, value_loc):
+        # XXX for now, we only trace 32-bit pointer-sized writes
+        self.mc.PUSH_r(eax.value)
+        self.mc.PUSH_r(ecx.value)
+        self.mc.PUSH_r(edx.value)
+        self.mc.PUSH_r(edx.value)
+        self.mc.PUSH_r(edx.value) # 5 pushes + 3 args, keeps 16-bytes alignment
+        # use the current address as the mark
+        self.mc.CALL_l(0)    # this is equivalent to "PUSH(IP)"
+        # push the newvalue
+        self.mc.PUSH(value_loc)
+        # push the address in which we are about to write
+        self.mc.LEA(eax, dest_addr)
+        self.mc.PUSH_r(eax.value)
+        # call (as an indirect call, to avoid needing a relative displacement)
+        self.mc.MOV_ri(eax.value, trace.addr_of_trace_set)
+        self.mc.CALL_r(eax.value)
+        # cancel the 8 pushes
+        self.mc.ADD_ri(esp.value, 5 * WORD)
+        self.mc.POP_r(edx.value)
+        self.mc.POP_r(ecx.value)
+        self.mc.POP_r(eax.value)
+
+    def save_into_mem(self, dest_addr, value_loc, size_loc, is_gc):
         size = size_loc.value
         if isinstance(value_loc, RegLoc) and value_loc.is_xmm:
             self.mc.MOVSD(dest_addr, value_loc)
@@ -1262,6 +1286,8 @@
         elif size == 2:
             self.mc.MOV16(dest_addr, value_loc)
         elif size == 4:
+            if IS_X86_32 and trace.is_tracing() and is_gc:
+                self.generate_ll_trace(dest_addr, value_loc)
             self.mc.MOV32(dest_addr, value_loc)
         elif size == 8:
             if IS_X86_64:
@@ -1298,7 +1324,8 @@
         base_loc, ofs_loc, size_loc, value_loc = arglocs
         assert isinstance(size_loc, ImmedLoc)
         dest_addr = AddressLoc(base_loc, ofs_loc)
-        self.save_into_mem(dest_addr, value_loc, size_loc)
+        self.save_into_mem(dest_addr, value_loc, size_loc,
+                           op.getopnum() == rop.SETFIELD_GC)
 
     def genop_discard_setarrayitem_gc(self, op, arglocs):
         base_loc, ofs_loc, value_loc, size_loc, baseofs = arglocs
@@ -1306,7 +1333,8 @@
         assert isinstance(size_loc, ImmedLoc)
         scale = _get_scale(size_loc.value)
         dest_addr = AddressLoc(base_loc, ofs_loc, scale, baseofs.value)
-        self.save_into_mem(dest_addr, value_loc, size_loc)
+        self.save_into_mem(dest_addr, value_loc, size_loc,
+                           op.getopnum() == rop.SETARRAYITEM_GC)
 
     def genop_discard_strsetitem(self, op, arglocs):
         base_loc, ofs_loc, val_loc = arglocs

diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py
--- a/pypy/jit/backend/llsupport/llmodel.py
+++ b/pypy/jit/backend/llsupport/llmodel.py
@@ -18,6 +18,7 @@
 from pypy.jit.backend.llsupport.descr import BaseIntCallDescr, GcPtrCallDescr
 from pypy.jit.backend.llsupport.descr import FloatCallDescr, VoidCallDescr
 from pypy.jit.backend.llsupport.asmmemmgr import AsmMemoryManager
+from pypy.jit.backend.llsupport.trace import trace_set
 from pypy.rpython.annlowlevel import cast_instance_to_base_ptr
 
 
@@ -325,6 +326,9 @@
         ofs, size, sign = self.unpack_arraydescr_size(arraydescr)
         # --- start of GC unsafe code (no GC operation!) ---
         items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs)
+        if lltype.typeOf(gcref) is not lltype.Signed:
+            trace_set(rffi.ptradd(items, itemindex * size),
+                      rffi.cast(rffi.LONG, newvalue), -100-size)
         for TYPE, _, itemsize in unroll_basic_sizes:
             if size == itemsize:
                 items = rffi.cast(rffi.CArrayPtr(TYPE), items)
@@ -339,6 +343,8 @@
         self.gc_ll_descr.do_write_barrier(gcref, newvalue)
         # --- start of GC unsafe code (no GC operation!) ---
         items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs)
+        trace_set(rffi.ptradd(items, itemindex * WORD),
+                  rffi.cast(rffi.LONG, newvalue), -99)
         items = rffi.cast(rffi.CArrayPtr(lltype.Signed), items)
         items[itemindex] = self.cast_gcref_to_int(newvalue)
         # --- end of GC unsafe code ---
@@ -348,6 +354,9 @@
         ofs = self.unpack_arraydescr(arraydescr)
         # --- start of GC unsafe code (no GC operation!) ---
         items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs)
+        if lltype.typeOf(gcref) is not lltype.Signed:
+            trace_set(rffi.ptradd(items, itemindex * symbolic.SIZEOF_FLOAT),
+                      rffi.cast(rffi.LONG, newvalue), -98)
         items = rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), items)
         items[itemindex] = newvalue
         # --- end of GC unsafe code ---
@@ -426,6 +435,8 @@
         ofs, size, sign = self.unpack_fielddescr_size(fielddescr)
         # --- start of GC unsafe code (no GC operation!) ---
         fieldptr = rffi.ptradd(rffi.cast(rffi.CCHARP, struct), ofs)
+        if lltype.typeOf(struct) is not lltype.Signed:
+            trace_set(fieldptr, rffi.cast(rffi.LONG, newvalue), -10)
         for TYPE, _, itemsize in unroll_basic_sizes:
             if size == itemsize:
                 fieldptr = rffi.cast(rffi.CArrayPtr(TYPE), fieldptr)
@@ -443,6 +454,7 @@
         self.gc_ll_descr.do_write_barrier(struct, newvalue)
         # --- start of GC unsafe code (no GC operation!) ---
         fieldptr = rffi.ptradd(rffi.cast(rffi.CCHARP, struct), ofs)
+        trace_set(fieldptr, rffi.cast(rffi.LONG, newvalue), -9)
         fieldptr = rffi.cast(rffi.CArrayPtr(lltype.Signed), fieldptr)
         fieldptr[0] = self.cast_gcref_to_int(newvalue)
         # --- end of GC unsafe code ---
@@ -452,6 +464,8 @@
         ofs = self.unpack_fielddescr(fielddescr)
         # --- start of GC unsafe code (no GC operation!) ---
         fieldptr = rffi.ptradd(rffi.cast(rffi.CCHARP, struct), ofs)
+        if lltype.typeOf(struct) is not lltype.Signed:
+            trace_set(fieldptr, rffi.cast(rffi.LONG, newvalue), -8)
         fieldptr = rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), fieldptr)
         fieldptr[0] = newvalue
         # --- end of GC unsafe code ---

diff --git a/pypy/translator/c/src/debug_lltrace.h b/pypy/translator/c/src/debug_lltrace.h
--- a/pypy/translator/c/src/debug_lltrace.h
+++ b/pypy/translator/c/src/debug_lltrace.h
@@ -1,18 +1,21 @@
 
-void _RPyTraceSet(void *addr, long newvalue, int mark);
+void _RPyTraceSet(void *addr, long newvalue, long mark);
 
 
 #ifndef RPY_LL_TRACE /****************************************/
 
+
+#  define RPY_IS_TRACING           0
 #  define RPyTraceSet(ptr, mark)   /* nothing */
 #  ifndef PYPY_NOT_MAIN_FILE
-void _RPyTraceSet(void *addr, long newvalue, int mark) { }
+void _RPyTraceSet(void *addr, long newvalue, long mark) { }
 #  endif
 
 
 #else /*******************************************************/
 
 
+#  define RPY_IS_TRACING           1
 #  define RPyTraceSet(ptr, mark)   _RPyTraceSet(&(ptr), (long)(ptr), mark)
 
 #  ifndef PYPY_NOT_MAIN_FILE
@@ -26,15 +29,15 @@
 static struct _RPyTrace_s *_RPyTrace_start   = NULL;
 static struct _RPyTrace_s *_RPyTrace_stop    = NULL;
 static struct _RPyTrace_s *_RPyTrace_current = NULL;
-static int _RPyTrace_default_size = 134217728;
+static const long _RPyTrace_default_size = 134217728;
 
 void _RPyTrace_WrapAround(void)
 {
   if (_RPyTrace_start == NULL)
     {
-      char *csize = getenv("PYPYTRACE");
-      int size = csize ? atoi(csize) : 0;
-      if (size <= 0)
+      char *csize = getenv("PYPYTRACEBUF");
+      long size = csize ? atol(csize) : 0;
+      if (size <= 1)
         size = _RPyTrace_default_size;
       _RPyTrace_start = malloc(size * sizeof(struct _RPyTrace_s));
       RPyAssert(_RPyTrace_start, "not enough memory to allocate the trace");
@@ -46,7 +49,7 @@
           (long)(_RPyTrace_stop - _RPyTrace_start));
 }
 
-void _RPyTraceSet(void *addr, long newvalue, int mark)
+void _RPyTraceSet(void *addr, long newvalue, long mark)
 {
   if (_RPyTrace_current == _RPyTrace_stop)
     _RPyTrace_WrapAround();

diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py
--- a/pypy/jit/backend/x86/test/test_ztranslation.py
+++ b/pypy/jit/backend/x86/test/test_ztranslation.py
@@ -36,6 +36,11 @@
 
             def __init__(self, i):
                 self.i = i
+                self.a = None
+
+        class A(object):
+            def __init__(self, next):
+                self.next = next
 
         @dont_look_inside
         def myabs(x):
@@ -64,6 +69,7 @@
                 k = myabs(j)
                 if k - abs(j):  raise ValueError
                 if k - abs(-j): raise ValueError
+                frame.a = A(frame.a)
             return total * 10
         #
         from pypy.rpython.lltypesystem import lltype, rffi


More information about the Pypy-commit mailing list