1. Pypy
  2. Untitled project
  3. pypy

Commits

Armin Rigo  committed 296023b

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

  • Participants
  • Parent commits 7cd9093
  • Branches lltrace

Comments (0)

Files changed (5)

File pypy/jit/backend/llsupport/llmodel.py

View file
 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
 
 
         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)
         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 ---
         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 ---
         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)
         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 ---
         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 ---

File pypy/jit/backend/llsupport/trace.py

View file
+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

File pypy/jit/backend/x86/assembler.py

View file
 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
         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)
         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:
         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
         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

File pypy/jit/backend/x86/test/test_ztranslation.py

View file
 
             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):
                 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

File pypy/translator/c/src/debug_lltrace.h

View file
 
-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
 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");
           (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();