Fixed a minor bug -- the condition for determining whether
VG_(handle_esp_assignment)() was needed by a skin (and thus whether to register
it in the baseBlock) was different to that used when determining whether to
call it in code generation... so it could be (attempted to be) called having
not been registered.

Fixed this by consistifying the conditions, using a function
VG_(need_to_handle_esp_assignment)() that is used in both places.  The bug
hadn't been found previously because no existing skin exercised the mismatched
conditions in conflicting ways.

Also took VG_(track).post_mem_write out of consideration because it's no longer
important (due to a change in how stack switching is detected).

----
Improved the error message for when a helper can't be found in the baseBlock --
now looks up the debug info to tell you the name of the not-found function.

----
Increased the number of noncompact helpers allowed from 8 to 24

----
Removed a magic number that was hardcoded all over the place, introducing
VG_MAX_REGS_USED for the size of the arrays needed by VG_(get_reg_usage)()

----
Also added these functions

   VG_(get_archreg)()
   VG_(get_thread_archreg)()
   VG_(get_thread_shadow_archreg)()
   VG_(set_thread_shadow_archreg)()

which can be useful for skins.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1419 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_from_ucode.c b/coregrind/vg_from_ucode.c
index c9c7f9f..a70f157 100644
--- a/coregrind/vg_from_ucode.c
+++ b/coregrind/vg_from_ucode.c
@@ -1767,6 +1767,7 @@
 Int VG_(helper_offset)(Addr a)
 {
    Int i;
+   Char buf[100];
 
    for (i = 0; i < VG_(n_compact_helpers); i++)
       if (VG_(compact_helper_addrs)[i] == a)
@@ -1776,9 +1777,11 @@
          return VG_(noncompact_helper_offsets)[i];
 
    /* Shouldn't get here */
+   VG_(get_fnname)   ( a, buf, 100 );
+
    VG_(printf)(
-      "\nCouldn't find offset of helper from its address (%p).\n"
-      "A helper function probably used hasn't been registered?\n\n", a);
+      "\nCouldn't find offset of helper from its address (%p: %s).\n"
+      "A helper function probably used hasn't been registered?\n\n", a, buf);
 
    VG_(printf)("      compact helpers: ");
    for (i = 0; i < VG_(n_compact_helpers); i++)
@@ -2704,6 +2707,41 @@
    }
 }
 
+UInt VG_(get_archreg) ( UInt arch )
+{
+   switch (arch) {
+      case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
+      case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
+      case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
+      case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
+      case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
+      case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
+      case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
+      case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
+      default:    VG_(core_panic)( "get_thread_archreg");
+   }
+}
+
+UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
+{
+   ThreadState* tst;
+
+   vg_assert(VG_(is_valid_tid)(tid));
+   tst = & VG_(threads)[tid];
+
+   switch (arch) {
+      case R_EAX: return tst->m_eax;
+      case R_ECX: return tst->m_ecx;
+      case R_EDX: return tst->m_edx;
+      case R_EBX: return tst->m_ebx;
+      case R_ESP: return tst->m_esp;
+      case R_EBP: return tst->m_ebp;
+      case R_ESI: return tst->m_esi;
+      case R_EDI: return tst->m_edi;
+      default:    VG_(core_panic)( "get_thread_archreg");
+   }
+}
+
 /* Return the baseBlock index for the specified shadow register */
 Int shadow_reg_index ( Int arch )
 {
@@ -2743,12 +2781,51 @@
    VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
 }
 
+UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
+{
+   ThreadState* tst;
+
+   vg_assert(VG_(is_valid_tid)(tid));
+   tst = & VG_(threads)[tid];
+
+   switch (archreg) {
+      case R_EAX: return tst->sh_eax;
+      case R_ECX: return tst->sh_ecx;
+      case R_EDX: return tst->sh_edx; 
+      case R_EBX: return tst->sh_ebx; 
+      case R_ESP: return tst->sh_esp; 
+      case R_EBP: return tst->sh_ebp; 
+      case R_ESI: return tst->sh_esi; 
+      case R_EDI: return tst->sh_edi; 
+      default:    VG_(core_panic)( "get_thread_shadow_archreg");
+   }
+}
+
+void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
+{
+   ThreadState* tst;
+
+   vg_assert(VG_(is_valid_tid)(tid));
+   tst = & VG_(threads)[tid];
+
+   switch (archreg) {
+      case R_EAX: tst->sh_eax = val; break;
+      case R_ECX: tst->sh_ecx = val; break;
+      case R_EDX: tst->sh_edx = val; break;
+      case R_EBX: tst->sh_ebx = val; break;
+      case R_ESP: tst->sh_esp = val; break;
+      case R_EBP: tst->sh_ebp = val; break;
+      case R_ESI: tst->sh_esi = val; break;
+      case R_EDI: tst->sh_edi = val; break;
+      default:    VG_(core_panic)( "set_thread_shadow_archreg");
+   }
+}
+
 Addr VG_(shadow_archreg_address) ( UInt archreg )
 {
    return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
 }
 
-
 static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
 {
    if (sz_src == 1 && sz_dst == 4) {
@@ -2910,11 +2987,7 @@
          if (u->tag2 == ArchReg 
              && u->val2 == R_ESP
              && u->size == 4
-             && (VG_(track_events).new_mem_stack         || 
-                 VG_(track_events).new_mem_stack_aligned ||
-                 VG_(track_events).die_mem_stack         ||
-                 VG_(track_events).die_mem_stack_aligned ||
-                 VG_(track_events).post_mem_write))
+             && VG_(need_to_handle_esp_assignment)())
          {
             synth_handle_esp_assignment ( i, u->val1, regs_live_before,
                                           u->regs_live_after );
diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h
index a17661c..86e024f 100644
--- a/coregrind/vg_include.h
+++ b/coregrind/vg_include.h
@@ -1322,6 +1322,9 @@
 extern void VG_(copy_baseBlock_to_m_state_static) ( void );
 extern void VG_(copy_m_state_static_to_baseBlock) ( void );
 
+/* Determine if VG_(handle_esp_assignment)() will be used */
+extern Bool VG_(need_to_handle_esp_assignment) ( void );
+
 /* Called when some unhandleable client behaviour is detected.
    Prints a msg and aborts. */
 extern void VG_(unimplemented) ( Char* msg )
diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c
index feb9fd7..a7d9ad9 100644
--- a/coregrind/vg_main.c
+++ b/coregrind/vg_main.c
@@ -105,7 +105,7 @@
 /* MAX_NONCOMPACT_HELPERS can be increased easily.  If MAX_COMPACT_HELPERS is
  * increased too much, they won't really be compact any more... */
 #define  MAX_COMPACT_HELPERS     8
-#define  MAX_NONCOMPACT_HELPERS  8 
+#define  MAX_NONCOMPACT_HELPERS  24 
 
 UInt VG_(n_compact_helpers)    = 0;
 UInt VG_(n_noncompact_helpers) = 0;
@@ -177,13 +177,21 @@
    for (i = 0; i < n; i++) offsets[i] = alloc_BaB_1_set( addrs[i] );
 }
 
+/* Will we need to call VG_(handle_esp_assignment)() ? */
+Bool VG_(need_to_handle_esp_assignment)(void)
+{
+   return (VG_(track_events).new_mem_stack         || 
+           VG_(track_events).new_mem_stack_aligned || 
+           VG_(track_events).die_mem_stack         ||
+           VG_(track_events).die_mem_stack_aligned);
+}
+
 /* Here we assign actual offsets.  It's important to get the most
    popular referents within 128 bytes of the start, so we can take
    advantage of short addressing modes relative to %ebp.  Popularity
    of offsets was measured on 22 Feb 02 running a KDE application, and
    the slots rearranged accordingly, with a 1.5% reduction in total
    size of translations. */
-
 static void vg_init_baseBlock ( void )
 {
    /* Those with offsets under 128 are carefully chosen. */
@@ -216,8 +224,7 @@
 
    /* (9 or 18) + n_compact_helpers  */
    /* Register VG_(handle_esp_assignment) if needed. */
-   if (VG_(track_events).new_mem_stack_aligned || 
-       VG_(track_events).die_mem_stack_aligned) 
+   if (VG_(need_to_handle_esp_assignment)())
       VG_(register_compact_helper)( (Addr) & VG_(handle_esp_assignment) );
 
    /* Allocate slots for compact helpers */
diff --git a/coregrind/vg_translate.c b/coregrind/vg_translate.c
index 1b30f15..e1c4984 100644
--- a/coregrind/vg_translate.c
+++ b/coregrind/vg_translate.c
@@ -1273,8 +1273,8 @@
 Bool uInstrMentionsTempReg ( UInstr* u, Int tempreg )
 {
    Int i, k;
-   Int tempUse[3];
-   Bool notUsed[3];
+   Int tempUse[VG_MAX_REGS_USED];
+   Bool notUsed[VG_MAX_REGS_USED];
 
    k = VG_(get_reg_usage) ( u, TempReg, &tempUse[0], &notUsed[0] );
    for (i = 0; i < k; i++)
@@ -1300,8 +1300,8 @@
    Int     i, j, k, m, n, ar, tr, told, actual_areg;
    Int     areg_map[8];
    Bool    annul_put[8];
-   Int     tempUse[3];
-   Bool    isWrites[3];
+   Int     tempUse[VG_MAX_REGS_USED];
+   Bool    isWrites[VG_MAX_REGS_USED];
    UInstr* u;
    Bool    wr;
    Int*    last_live_before;
@@ -1641,9 +1641,9 @@
    Int          ss_busy_until_before[VG_MAX_SPILLSLOTS];
    Int          i, j, k, m, r, tno, max_ss_no;
    Bool         wr, defer, isRead, spill_reqd;
-   UInt         realUse[3];
-   Int          tempUse[3];
-   Bool         isWrites[3];
+   UInt         realUse[VG_MAX_REGS_USED];
+   Int          tempUse[VG_MAX_REGS_USED];
+   Bool         isWrites[VG_MAX_REGS_USED];
    UCodeBlock*  c2;
 
    /* Used to denote ... well, "no value" in this fn. */
@@ -1670,7 +1670,7 @@
    for (i = 0; i < c1->used; i++) {
       k = VG_(get_reg_usage)(&c1->instrs[i], TempReg, &tempUse[0],
                              &isWrites[0]);
-      vg_assert(k >= 0 && k <= 3);
+      vg_assert(k >= 0 && k <= VG_MAX_REGS_USED);
 
       /* For each temp usage ... fwds in program order */
       for (j = 0; j < k; j++) {
@@ -1811,7 +1811,7 @@
 
       k = VG_(get_reg_usage)(&c1->instrs[i], TempReg, &tempUse[0],
                              &isWrites[0]);
-      vg_assert(k >= 0 && k <= 3);
+      vg_assert(k >= 0 && k <= VG_MAX_REGS_USED);
 
       /* For each ***different*** temp mentioned in the insn .... */
       for (j = 0; j < k; j++) {
@@ -1980,8 +1980,8 @@
 {        
    Int      i, j, k;
    RRegSet  rregs_live;
-   Int      regUse[3];
-   Bool     isWrites[3];
+   Int      regUse[VG_MAX_REGS_USED];
+   Bool     isWrites[VG_MAX_REGS_USED];
    UInstr*  u;
 
    /* All regs are dead at the end of the block */