]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Redo the dispatcher's fast-cache mechanism (VG_(tt_fast) et al) to be
authorJulian Seward <jseward@acm.org>
Sun, 11 Feb 2007 05:08:06 +0000 (05:08 +0000)
committerJulian Seward <jseward@acm.org>
Sun, 11 Feb 2007 05:08:06 +0000 (05:08 +0000)
more cache friendly.  This changes the mechanism from being a table of
pointers to (guest address, translated code pairs) to being a table of
pairs (guest address, pointer to translated code).  The effect ranges
from zero up to about 20% performance improvement on memcheck, the
biggest effects being seen for programs which jump around a large
number of blocks of code and whose data set does not fit in L2.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@6582

coregrind/m_dispatch/dispatch-amd64-linux.S
coregrind/m_dispatch/dispatch-ppc32-linux.S
coregrind/m_dispatch/dispatch-x86-linux.S
coregrind/m_translate.c
coregrind/m_transtab.c
coregrind/pub_core_transtab.h

index 4e1fe001262a1060f93be6555061082b42fe8efa..2cd683133c6df6f895ebda14fc4a45676fcfa336 100644 (file)
@@ -119,8 +119,12 @@ VG_(run_innerloop__dispatch_unprofiled):
        /* AT ENTRY: %rax is next guest addr, %rbp is possibly
            modified guest state ptr */
 
-       /* Has the guest state pointer been messed with?  If yes, exit. */
+       /* Has the guest state pointer been messed with?  If yes, exit.
+           Also, set %rcx to be &VG_(tt_fast), some insns before it is
+           used, in the hope of getting it off the critical path.  This
+           location seems to be optimal on 2.2GHz Athlon64. */
        cmpq    8(%rsp), %rbp
+       movq    VG_(tt_fast)@GOTPCREL(%rip), %rcx
        jnz     gsp_changed
 
        /* save the jump address in the guest state */
@@ -131,17 +135,16 @@ VG_(run_innerloop__dispatch_unprofiled):
        jz      counter_is_zero
 
        /* try a fast lookup in the translation cache */
-       movq    VG_(tt_fast)@GOTPCREL(%rip), %rcx
-       movq    %rax, %rbx
-       andq    $VG_TT_FAST_MASK, %rbx
-       movq    (%rcx,%rbx,8), %rcx
-       cmpq    %rax, (%rcx)
+       movq    %rax, %rbx              /* next guest addr */
+       andq    $VG_TT_FAST_MASK, %rbx  /* entry# */
+       shlq    $4, %rbx                /* entry# * sizeof(FastCacheEntry) */
+       movq    0(%rcx,%rbx,1), %r10    /* .guest */
+       movq    8(%rcx,%rbx,1), %r11    /* .host */
+       cmpq    %rax, %r10
        jnz     fast_lookup_failed
 
-       /* Found a match.  Call tce[1], which is 8 bytes along, since
-           each tce element is a 64-bit int. */
-       addq    $8, %rcx
-       jmp     *%rcx
+        /* Found a match.  Jump to .host. */
+       jmp     *%r11
        ud2     /* persuade insn decoders not to speculate past here */
        /* generated code should run, then jump back to
           VG_(run_innerloop__dispatch_unprofiled). */
@@ -157,8 +160,12 @@ VG_(run_innerloop__dispatch_profiled):
        /* AT ENTRY: %rax is next guest addr, %rbp is possibly
            modified guest state ptr */
 
-       /* Has the guest state pointer been messed with?  If yes, exit. */
+       /* Has the guest state pointer been messed with?  If yes, exit.
+           Also, set %rcx to be &VG_(tt_fast), some insns before it is
+           used, in the hope of getting it off the critical path.  This
+           location seems to be optimal on 2.2GHz Athlon64. */
        cmpq    8(%rsp), %rbp
+       movq    VG_(tt_fast)@GOTPCREL(%rip), %rcx
        jnz     gsp_changed
 
        /* save the jump address in the guest state */
@@ -169,22 +176,22 @@ VG_(run_innerloop__dispatch_profiled):
        jz      counter_is_zero
 
        /* try a fast lookup in the translation cache */
-       movq    VG_(tt_fast)@GOTPCREL(%rip), %rcx
        movq    %rax, %rbx
-       andq    $VG_TT_FAST_MASK, %rbx
-       movq    (%rcx,%rbx,8), %rcx
-       cmpq    %rax, (%rcx)
+       andq    $VG_TT_FAST_MASK, %rbx  /* entry# */
+       shlq    $4, %rbx                /* entry# * sizeof(FastCacheEntry) */
+       movq    0(%rcx,%rbx,1), %r10    /* .guest */
+       movq    8(%rcx,%rbx,1), %r11    /* .host */
+       cmpq    %rax, %r10
        jnz     fast_lookup_failed
 
        /* increment bb profile counter */
        movq    VG_(tt_fastN)@GOTPCREL(%rip), %rdx
-       movq    (%rdx,%rbx,8), %rdx
+       shrq    $1, %rbx                /* entry# * sizeof(UInt*) */
+       movq    (%rdx,%rbx,1), %rdx
        addl    $1, (%rdx)
 
-       /* Found a match.  Call tce[1], which is 8 bytes along, since
-           each tce element is a 64-bit int. */
-       addq    $8, %rcx
-       jmp     *%rcx
+        /* Found a match.  Jump to .host. */
+       jmp     *%r11
        ud2     /* persuade insn decoders not to speculate past here */
        /* generated code should run, then jump back to
           VG_(run_innerloop__dispatch_profiled). */
index f4e12aa988e5d9a642b6a5bab65bc1e818366750..53f92ca9e599b58c0697ffd74974131efe973701 100644 (file)
@@ -8,7 +8,7 @@
   This file is part of Valgrind, a dynamic binary instrumentation
   framework.
 
-  Copyright (C) 2005 Cerion Armour-Brown <cerion@open-works.co.uk>
+  Copyright (C) 2005-2007 Cerion Armour-Brown <cerion@open-works.co.uk>
 
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
@@ -248,10 +248,13 @@ VG_(run_innerloop__dispatch_unprofiled):
           Stack state:
                44(r1) (=orig guest_state)
        */
-
-       /* Has the guest state pointer been messed with?  If yes, exit. */
-        lwz     5,44(1)         /* original guest_state ptr */
-        cmpw    5,31
+       /* Has the guest state pointer been messed with?  If yes, exit.
+           Also set up & VG_(tt_fast) to give the load time to come
+           through. */
+        lwz     9,44(1)              /* original guest_state ptr */
+        lis    5,VG_(tt_fast)@ha
+        addi    5,5,VG_(tt_fast)@l   /* & VG_(tt_fast) */
+        cmpw    9,31
         bne    gsp_changed
 
         /* save the jump address in the guest state */
@@ -264,20 +267,16 @@ VG_(run_innerloop__dispatch_unprofiled):
 
         /* try a fast lookup in the translation cache */
         /* r4 = VG_TT_FAST_HASH(addr)           * sizeof(ULong*)
-              = ((r3 >>u 2) & VG_TT_FAST_MASK)  << 2 */
-        rlwinm  4,3, 0, 32-2-VG_TT_FAST_BITS, 31-2  
-        addis   5,4,VG_(tt_fast)@ha
-        lwz     5,VG_(tt_fast)@l(5)
-        lwz     6,4(5)   /* big-endian, so comparing 2nd 32bit word */
+              = ((r3 >>u 2) & VG_TT_FAST_MASK)  << 3 */
+       rlwinm  4,3,1, 29-VG_TT_FAST_BITS, 28   /* entry# * 8 */
+       add     5,5,4   /* & VG_(tt_fast)[entry#] */
+       lwz     6,0(5)   /* .guest */
+       lwz     7,4(5)   /* .host */
         cmpw    3,6
         bne     fast_lookup_failed
 
-        /* Found a match.  Call tce[1], which is 8 bytes along, since
-           each tce element is a 64-bit int. */
-        addi    8,5,8
-        mtctr   8
-
-       /* run the translation */
+        /* Found a match.  Call .host. */
+        mtctr   7
         bctrl
 
         /* On return from guest code:
@@ -285,7 +284,6 @@ VG_(run_innerloop__dispatch_unprofiled):
            r31 may be unchanged (guest_state), or may indicate further
            details of the control transfer requested to *r3.
         */
-
        /* start over */
        b       VG_(run_innerloop__dispatch_unprofiled)
        /*NOTREACHED*/
@@ -304,10 +302,13 @@ VG_(run_innerloop__dispatch_profiled):
           Stack state:
                44(r1) (=orig guest_state)
        */
-
-       /* Has the guest state pointer been messed with?  If yes, exit. */
-        lwz     5,44(1)         /* original guest_state ptr */
-        cmpw    5,31
+       /* Has the guest state pointer been messed with?  If yes, exit.
+           Also set up & VG_(tt_fast) to give the load time to come
+           through. */
+        lwz     9,44(1)              /* original guest_state ptr */
+        lis    5,VG_(tt_fast)@ha
+        addi    5,5,VG_(tt_fast)@l   /* & VG_(tt_fast) */
+        cmpw    9,31
         bne    gsp_changed
 
         /* save the jump address in the guest state */
@@ -320,27 +321,24 @@ VG_(run_innerloop__dispatch_profiled):
 
         /* try a fast lookup in the translation cache */
         /* r4 = VG_TT_FAST_HASH(addr)           * sizeof(ULong*)
-              = ((r3 >>u 2) & VG_TT_FAST_MASK)  << 2 */
-        rlwinm  4,3, 0, 32-2-VG_TT_FAST_BITS, 31-2 
-        addis   5,4,VG_(tt_fast)@ha
-        lwz     5,VG_(tt_fast)@l(5)
-        lwz     6,4(5)   /* big-endian, so comparing 2nd 32bit word */
+              = ((r3 >>u 2) & VG_TT_FAST_MASK)  << 3 */
+       rlwinm  4,3,1, 29-VG_TT_FAST_BITS, 28   /* entry# * 8 */
+       add     5,5,4   /* & VG_(tt_fast)[entry#] */
+       lwz     6,0(5)   /* .guest */
+       lwz     7,4(5)   /* .host */
         cmpw    3,6
         bne     fast_lookup_failed
 
         /* increment bb profile counter */
+       srwi    4,4,1   /* entry# * 4 */
         addis   6,4,VG_(tt_fastN)@ha
-        lwz     7,VG_(tt_fastN)@l(6)
-        lwz     8,0(7)
+        lwz     9,VG_(tt_fastN)@l(6)
+        lwz     8,0(9)
         addi    8,8,1
-        stw     8,0(7)
+        stw     8,0(9)
 
-        /* Found a match.  Call tce[1], which is 8 bytes along, since
-           each tce element is a 64-bit int. */
-        addi    8,5,8
-        mtctr   8
-
-       /* run the translation */
+        /* Found a match.  Call .host. */
+        mtctr   7
         bctrl
 
         /* On return from guest code:
@@ -348,7 +346,6 @@ VG_(run_innerloop__dispatch_profiled):
            r31 may be unchanged (guest_state), or may indicate further
            details of the control transfer requested to *r3.
         */
-
        /* start over */
        b       VG_(run_innerloop__dispatch_profiled)
        /*NOTREACHED*/
index 8ffe813f1df75bed4a74957ee5c92ee3e58fcf0d..5cf10c493d138b925726c1647b75f83a12f7c623 100644 (file)
@@ -120,16 +120,15 @@ VG_(run_innerloop__dispatch_unprofiled):
        jz      counter_is_zero
 
        /* try a fast lookup in the translation cache */
-       movl    %eax, %ebx
-       andl    $VG_TT_FAST_MASK, %ebx
-       movl    VG_(tt_fast)(,%ebx,4), %ecx
-       cmpl    %eax, (%ecx)
+       movl    %eax, %ebx                      /* next guest addr */
+       andl    $VG_TT_FAST_MASK, %ebx          /* entry# */
+       movl    0+VG_(tt_fast)(,%ebx,8), %esi   /* .guest */
+       movl    4+VG_(tt_fast)(,%ebx,8), %edi   /* .host */
+       cmpl    %eax, %esi
        jnz     fast_lookup_failed
 
-       /* Found a match.  Jump to tce[1], which is 8 bytes along,
-       since each tce element is a 64-bit int. */
-       addl    $8, %ecx
-       jmp     *%ecx
+       /* Found a match.  Jump to .host. */
+       jmp     *%edi
        ud2     /* persuade insn decoders not to speculate past here */
        /* generated code should run, then jump back to
           VG_(run_innerloop__dispatch_unprofiled). */
@@ -157,11 +156,13 @@ VG_(run_innerloop__dispatch_profiled):
        jz      counter_is_zero
 
        /* try a fast lookup in the translation cache */
-       movl    %eax, %ebx
-       andl    $VG_TT_FAST_MASK, %ebx
-       movl    VG_(tt_fast)(,%ebx,4), %ecx
-       cmpl    %eax, (%ecx)
+       movl    %eax, %ebx                      /* next guest addr */
+       andl    $VG_TT_FAST_MASK, %ebx          /* entry# */
+       movl    0+VG_(tt_fast)(,%ebx,8), %esi   /* .guest */
+       movl    4+VG_(tt_fast)(,%ebx,8), %edi   /* .host */
+       cmpl    %eax, %esi
        jnz     fast_lookup_failed
+
        /* increment bb profile counter */
        /* note: innocuous as this sounds, it causes a huge amount more
            stress on D1 and significantly slows everything down. */
@@ -169,10 +170,8 @@ VG_(run_innerloop__dispatch_profiled):
        /* Use "addl $1", not "incl", to avoid partial-flags stall on P4 */
        addl    $1, (%edx)
 
-       /* Found a match.  Jump to tce[1], which is 8 bytes along,
-       since each tce element is a 64-bit int. */
-       addl    $8, %ecx
-       jmp     *%ecx
+       /* Found a match.  Jump to .host. */
+       jmp     *%edi
        ud2     /* persuade insn decoders not to speculate past here */
        /* generated code should run, then jump back to
           VG_(run_innerloop__dispatch_profiled). */
index d0b7d53d17287c345bf721fb4d93ae7963bd8a23..0640002e89a4b610127f31a45c1d6a7f9e979168 100644 (file)
@@ -577,6 +577,12 @@ static Bool chase_into_ok ( void* closureV, Addr64 addr64 )
       goto dontchase;
 #  endif
 
+   /* overly conservative, but .. don't chase into the distinguished
+      address that m_transtab uses as an empty-slot marker for
+      VG_(tt_fast). */
+   if (addr == TRANSTAB_BOGUS_GUEST_ADDR)
+      goto dontchase;
+
    /* well, ok then.  go on and chase. */
    return True;
 
@@ -1155,7 +1161,8 @@ Bool VG_(translate) ( ThreadId tid,
    { /* BEGIN new scope specially for 'seg' */
    NSegment const* seg = VG_(am_find_nsegment)(addr);
 
-   if (!translations_allowable_from_seg(seg)) {
+   if ( (!translations_allowable_from_seg(seg))
+        || addr == TRANSTAB_BOGUS_GUEST_ADDR ) {
       if (VG_(clo_trace_signals))
          VG_(message)(Vg_DebugMsg, "translations not allowed here "
                                    "- throwing SEGV");
index ac8a7602d3cc4c622e3b8f086fe86cb48efc8735..f1c523f7783a137986f0b6b2f415eb24bb444109 100644 (file)
 
 /*------------------ TYPES ------------------*/
 
-/* A translation-cache entry is two parts:
-   - The guest address of the first (entry) bb in the translation,
-     as a 64-bit word.
-   - One or more 64-bit words containing the code.
-   It is supposed to be 64-bit aligned.
-*/
-/*
-typedef
-   struct {
-      Addr64 orig_addr;
-      ULong  code[0];
-   }
-   TCEntry;
-*/
-
 /* A translation-table entry.  This indicates precisely which areas of
    guest code are included in the translation, and contains all other
    auxiliary info too.  */
@@ -117,9 +102,10 @@ typedef
          deletion, hence the Deleted state. */
       enum { InUse, Deleted, Empty } status;
 
-      /* Pointer to the corresponding TCEntry (must be in the same
-         sector!) */
-      ULong* tce;
+      /* 64-bit aligned pointer to one or more 64-bit words containing
+         the corresponding host code (must be in the same sector!)
+         This is a pointer into the sector's tc (code) area. */
+      ULong* tcptr;
 
       /* This is the original guest address that purportedly is the
          entry point of the translation.  You might think that .entry
@@ -214,33 +200,48 @@ static Int    youngest_sector = -1;
 static Int    tc_sector_szQ;
 
 
-/* Fast helper for the TC.  A direct-mapped cache which holds a
-   pointer to a TC entry which may or may not be the correct one, but
-   which we hope usually is.  This array is referred to directly from
-   <arch>/dispatch.S.
+/* Fast helper for the TC.  A direct-mapped cache which holds a set of
+   recently used (guest address, host address) pairs.  This array is
+   referred to directly from m_dispatch/dispatch-<platform>.S.
 
-   Entries in tt_fast may point to any valid TC entry, regardless of
+   Entries in tt_fast may refer to any valid TC entry, regardless of
    which sector it's in.  Consequently we must be very careful to
    invalidate this cache when TC entries are changed or disappear.
 
-   A special TCEntry -- bogus_tc_entry -- must be pointed at to cause
-   that cache entry to miss.  This relies on the assumption that no
-   guest code actually has an address of 0x1.
+   A special .guest address - TRANSTAB_BOGUS_GUEST_ADDR -- must be
+   pointed at to cause that cache entry to miss.  This relies on the
+   assumption that no guest code actually has that address, hence a
+   value 0x1 seems good.  m_translate gives the client a synthetic
+   segfault if it tries to execute at this address.
+*/
+/*
+typedef
+   struct { 
+      Addr guest;
+      Addr host;
+   }
+   FastCacheEntry;
+*/
+/*global*/ __attribute__((aligned(16)))
+           FastCacheEntry VG_(tt_fast)[VG_TT_FAST_SIZE];
+/*
+#define TRANSTAB_BOGUS_GUEST_ADDR ((Addr)1)
 */
-/*global*/ ULong* VG_(tt_fast)[VG_TT_FAST_SIZE];
-
-static ULong bogus_tc_entry = (Addr64)1;
-
 
 /* For profiling, we have a parallel array of pointers to .count
    fields in TT entries.  Again, these pointers must be invalidated
    when translations disappear.  A NULL pointer suffices to indicate
    an unused slot.
 
-   tt_fast and tt_fastN change together: if tt_fast[i] points to
-   bogus_tc_entry then the corresponding tt_fastN[i] must be null.  If
-   tt_fast[i] points to some TC entry somewhere, then tt_fastN[i]
-   *must* point to the .count field of the corresponding TT entry.
+   When not profiling (the normal case, VG_(clo_profile_flags) == 0),
+   all tt_fastN entries are set to NULL at startup and never read nor
+   written after that.
+
+   When profiling (VG_(clo_profile_flags) > 0), tt_fast and tt_fastN
+   change together: if tt_fast[i].guest is TRANSTAB_BOGUS_GUEST_ADDR
+   then the corresponding tt_fastN[i] must be null.  If
+   tt_fast[i].guest is any other value, then tt_fastN[i] *must* point
+   to the .count field of the corresponding TT entry.
 
    tt_fast and tt_fastN are referred to from assembly code
    (dispatch.S).
@@ -557,8 +558,9 @@ static Bool sanity_check_eclasses_in_sector ( Sector* sec )
 
 /* Sanity check absolutely everything.  True == check passed. */
 
-/* forward */
+/* forwards */
 static Bool sanity_check_redir_tt_tc ( void );
+static Bool sanity_check_fastcache ( void );
 
 static Bool sanity_check_all_sectors ( void )
 {
@@ -573,7 +575,9 @@ static Bool sanity_check_all_sectors ( void )
       if (!sane)
          return False;
    }
-   if (!sanity_check_redir_tt_tc() )
+   if ( !sanity_check_redir_tt_tc() )
+      return False;
+   if ( !sanity_check_fastcache() )
       return False;
    return True;
 }
@@ -609,34 +613,81 @@ static inline UInt HASH_TT ( Addr64 key )
    return k32 % N_TTES_PER_SECTOR;
 }
 
-static void setFastCacheEntry ( Addr64 key, ULong* tce, UInt* count )
+static void setFastCacheEntry ( Addr64 key, ULong* tcptr, UInt* count )
 {
    UInt cno = (UInt)VG_TT_FAST_HASH(key);
-   VG_(tt_fast)[cno]  = tce;
-   VG_(tt_fastN)[cno] = VG_(clo_profile_flags) > 0  ? count  : NULL;
+   VG_(tt_fast)[cno].guest = (Addr)key;
+   VG_(tt_fast)[cno].host  = (Addr)tcptr;
+   if (VG_(clo_profile_flags) > 0)
+      VG_(tt_fastN)[cno] = count;
    n_fast_updates++;
+   /* This shouldn't fail.  It should be assured by m_translate
+      which should reject any attempt to make translation of code
+      starting at TRANSTAB_BOGUS_GUEST_ADDR. */
+   vg_assert(VG_(tt_fast)[cno].guest != TRANSTAB_BOGUS_GUEST_ADDR);
 }
 
-static void invalidateFastCache ( void )
+/* Invalidate the fast cache's counter array, VG_(tt_fastN). */
+static void invalidateFastNCache ( void )
 {
    UInt j;
-   /* This loop is popular enough to make it worth unrolling a
-      bit, at least on ppc32. */
    vg_assert(VG_TT_FAST_SIZE > 0 && (VG_TT_FAST_SIZE % 4) == 0);
    for (j = 0; j < VG_TT_FAST_SIZE; j += 4) {
-      VG_(tt_fast)[j+0]  = &bogus_tc_entry;
-      VG_(tt_fast)[j+1]  = &bogus_tc_entry;
-      VG_(tt_fast)[j+2]  = &bogus_tc_entry;
-      VG_(tt_fast)[j+3]  = &bogus_tc_entry;
       VG_(tt_fastN)[j+0] = NULL;
       VG_(tt_fastN)[j+1] = NULL;
       VG_(tt_fastN)[j+2] = NULL;
       VG_(tt_fastN)[j+3] = NULL;
    }
    vg_assert(j == VG_TT_FAST_SIZE);
+}
+
+/* Invalidate the fast cache VG_(tt_fast).  If profiling, also
+   invalidate the fast cache's counter array VG_(tt_fastN), otherwise
+   don't touch it. */
+static void invalidateFastCache ( void )
+{
+   UInt j;
+   /* This loop is popular enough to make it worth unrolling a
+      bit, at least on ppc32. */
+   vg_assert(VG_TT_FAST_SIZE > 0 && (VG_TT_FAST_SIZE % 4) == 0);
+   for (j = 0; j < VG_TT_FAST_SIZE; j += 4) {
+      VG_(tt_fast)[j+0].guest = TRANSTAB_BOGUS_GUEST_ADDR;
+      VG_(tt_fast)[j+1].guest = TRANSTAB_BOGUS_GUEST_ADDR;
+      VG_(tt_fast)[j+2].guest = TRANSTAB_BOGUS_GUEST_ADDR;
+      VG_(tt_fast)[j+3].guest = TRANSTAB_BOGUS_GUEST_ADDR;
+   }
+
+   if (VG_(clo_profile_flags) > 0)
+      invalidateFastNCache();
+
+   vg_assert(j == VG_TT_FAST_SIZE);
    n_fast_flushes++;
 }
 
+static Bool sanity_check_fastcache ( void )
+{
+   UInt j;
+   if (0) VG_(printf)("sanity check fastcache\n");
+   if (VG_(clo_profile_flags) > 0) {
+      /* profiling */
+      for (j = 0; j < VG_TT_FAST_SIZE; j++) {
+         if (VG_(tt_fastN)[j] == NULL 
+             && VG_(tt_fast)[j].guest != TRANSTAB_BOGUS_GUEST_ADDR)
+            return False;
+         if (VG_(tt_fastN)[j] != NULL 
+             && VG_(tt_fast)[j].guest == TRANSTAB_BOGUS_GUEST_ADDR)
+            return False;
+      }
+   } else {
+      /* not profiling */
+      for (j = 0; j < VG_TT_FAST_SIZE; j++) {
+         if (VG_(tt_fastN)[j] != NULL)
+            return False;
+      }
+   }
+   return True;
+}
+
 static void initialiseSector ( Int sno )
 {
    Int    i;
@@ -746,6 +797,9 @@ static void invalidate_icache ( void *ptr, Int nbytes )
    Addr addr;
    VexArchInfo vai;
 
+   if (nbytes == 0) return;
+   vg_assert(nbytes > 0);
+
    VG_(machine_get_VexArchInfo)( NULL, &vai );
    cls = vai.ppc_cache_line_szB;
 
@@ -785,7 +839,7 @@ void VG_(add_to_transtab)( VexGuestExtents* vge,
                            Bool             is_self_checking )
 {
    Int    tcAvailQ, reqdQ, y, i;
-   ULong  *tce, *tce2;
+   ULong  *tcptr, *tcptr2;
    UChar* srcP;
    UChar* dstP;
 
@@ -812,7 +866,7 @@ void VG_(add_to_transtab)( VexGuestExtents* vge,
       initialiseSector(y);
 
    /* Try putting the translation in this sector. */
-   reqdQ = 1 + ((code_len + 7) >> 3);
+   reqdQ = (code_len + 7) >> 3;
 
    /* Will it fit in tc? */
    tcAvailQ = ((ULong*)(&sectors[y].tc[tc_sector_szQ]))
@@ -852,12 +906,11 @@ void VG_(add_to_transtab)( VexGuestExtents* vge,
    vg_assert(sectors[y].tt_n_inuse >= 0);
  
    /* Copy into tc. */
-   tce = sectors[y].tc_next;
-   vg_assert(tce >= &sectors[y].tc[0]);
-   vg_assert(tce <= &sectors[y].tc[tc_sector_szQ]);
+   tcptr = sectors[y].tc_next;
+   vg_assert(tcptr >= &sectors[y].tc[0]);
+   vg_assert(tcptr <= &sectors[y].tc[tc_sector_szQ]);
 
-   tce[0] = entry;
-   dstP = (UChar*)(&tce[1]);
+   dstP = (UChar*)tcptr;
    srcP = (UChar*)code;
    for (i = 0; i < code_len; i++)
       dstP[i] = srcP[i];
@@ -867,9 +920,9 @@ void VG_(add_to_transtab)( VexGuestExtents* vge,
    invalidate_icache( dstP, code_len );
 
    /* more paranoia */
-   tce2 = sectors[y].tc_next;
-   vg_assert(tce2 >= &sectors[y].tc[0]);
-   vg_assert(tce2 <= &sectors[y].tc[tc_sector_szQ]);
+   tcptr2 = sectors[y].tc_next;
+   vg_assert(tcptr2 >= &sectors[y].tc[0]);
+   vg_assert(tcptr2 <= &sectors[y].tc[tc_sector_szQ]);
 
    /* Find an empty tt slot, and use it.  There must be such a slot
       since tt is never allowed to get completely full. */
@@ -885,14 +938,14 @@ void VG_(add_to_transtab)( VexGuestExtents* vge,
    }
 
    sectors[y].tt[i].status = InUse;
-   sectors[y].tt[i].tce    = tce;
+   sectors[y].tt[i].tcptr  = tcptr;
    sectors[y].tt[i].count  = 0;
    sectors[y].tt[i].weight = 1;
    sectors[y].tt[i].vge    = *vge;
    sectors[y].tt[i].entry  = entry;
 
    /* Update the fast-cache. */
-   setFastCacheEntry( entry, tce, &sectors[y].tt[i].count );
+   setFastCacheEntry( entry, tcptr, &sectors[y].tt[i].count );
 
    /* Note the eclass numbers for this translation. */
    upd_eclasses_after_add( &sectors[y], i );
@@ -934,10 +987,10 @@ Bool VG_(search_transtab) ( /*OUT*/AddrH* result,
             /* found it */
             if (upd_cache)
                setFastCacheEntry( 
-                  guest_addr, sectors[sno].tt[k].tce
+                  guest_addr, sectors[sno].tt[k].tcptr
                               &sectors[sno].tt[k].count );
             if (result)
-               *result = sizeof(Addr64) + (AddrH)sectors[sno].tt[k].tce;
+               *result = (AddrH)sectors[sno].tt[k].tcptr;
             return True;
          }
          if (sectors[sno].tt[k].status == Empty)
@@ -1392,6 +1445,14 @@ void VG_(init_tt_tc) ( void )
    /* Otherwise lots of things go wrong... */
    vg_assert(sizeof(ULong) == 8);
    vg_assert(sizeof(Addr64) == 8);
+   /* check fast cache entries really are 2 words long */
+   vg_assert(sizeof(Addr) == sizeof(void*));
+   vg_assert(sizeof(FastCacheEntry) == 2 * sizeof(Addr));
+   /* check fast cache entries are packed back-to-back with no spaces */
+   vg_assert(sizeof( VG_(tt_fast) ) == VG_TT_FAST_SIZE * sizeof(FastCacheEntry));
+   /* check fast cache is aligned as we requested.  Not fatal if it
+      isn't, but we might as well make sure. */
+   vg_assert(VG_IS_16_ALIGNED( ((Addr) & VG_(tt_fast)[0]) ));
 
    if (VG_(clo_verbosity) > 2)
       VG_(message)(Vg_DebugMsg, 
@@ -1420,8 +1481,12 @@ void VG_(init_tt_tc) ( void )
       }
    }
 
-   /* and the fast caches. */
+   /* Initialise the fast caches.  If not profiling (the usual case),
+      we have to explicitly invalidate the fastN cache as
+      invalidateFastCache() won't do that for us. */
    invalidateFastCache();
+   if (VG_(clo_profile_flags) == 0)
+      invalidateFastNCache();
 
    /* and the unredir tt/tc */
    init_unredir_tt_tc();
index 8858600a369d384c1e897de05edb27506870bcc4..9d277d40105240eb30dee2fe76e5acd2ee3baab5 100644 (file)
 
 #include "pub_core_transtab_asm.h"
 
-/* The fast-cache for tt-lookup, and for finding counters. */
-extern ULong* VG_(tt_fast) [VG_TT_FAST_SIZE];
-extern UInt*  VG_(tt_fastN)[VG_TT_FAST_SIZE];
+/* The fast-cache for tt-lookup, and for finding counters.  Unused
+   entries are denoted by .guest == 1, which is assumed to be a bogus
+   address for all guest code. */
+typedef
+   struct { 
+      Addr guest;
+      Addr host;
+   }
+   FastCacheEntry;
+
+extern __attribute__((aligned(16)))
+       FastCacheEntry VG_(tt_fast) [VG_TT_FAST_SIZE];
+
+#define TRANSTAB_BOGUS_GUEST_ADDR ((Addr)1)
+
+extern UInt*          VG_(tt_fastN)[VG_TT_FAST_SIZE];
 
 extern void VG_(init_tt_tc)       ( void );