blob: ff264faa99e79b50c9c6a8b321295ccaeb3e7f9c [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
3/*--- Management of the translation table and cache. ---*/
4/*--- vg_transtab.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
njnc9539842002-10-02 13:26:35 +00008 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
sewardjde4a1d02002-03-22 01:27:54 +000010
11 Copyright (C) 2000-2002 Julian Seward
12 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000030*/
31
32#include "vg_include.h"
sewardj22854b92002-11-30 14:00:47 +000033#include <stddef.h>
sewardjde4a1d02002-03-22 01:27:54 +000034
sewardj18d75132002-05-16 11:06:21 +000035/* #define DEBUG_TRANSTAB */
36
sewardjde4a1d02002-03-22 01:27:54 +000037
sewardj6c3769f2002-11-29 01:02:45 +000038/*-------------------------------------------------------------*/
39/*--- Management of the FIFO-based translation table+cache. ---*/
40/*-------------------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +000041
sewardj6c3769f2002-11-29 01:02:45 +000042/*------------------ CONSTANTS ------------------*/
sewardjde4a1d02002-03-22 01:27:54 +000043
sewardj6c3769f2002-11-29 01:02:45 +000044/* Number of sectors the TC is divided into. */
45#define VG_TC_N_SECTORS 8
sewardjde4a1d02002-03-22 01:27:54 +000046
sewardjc0d8f682002-11-30 00:49:43 +000047/* Calculated once at startup and never changed. */
48/* const */ Int vg_tc_sector_szB = 0;
sewardjde4a1d02002-03-22 01:27:54 +000049
50/* Number of entries in the translation table. This must be a prime
51 number in order to make the hashing work properly. */
sewardj18d75132002-05-16 11:06:21 +000052#define VG_TT_SIZE /*5281*/ /*100129*/ 200191 /*250829*/
sewardjde4a1d02002-03-22 01:27:54 +000053
54/* Do an LRU pass when the translation table becomes this full. */
55#define VG_TT_LIMIT_PERCENT /*67*/ 80
56
sewardj6c3769f2002-11-29 01:02:45 +000057#define VG_TT_LIMIT ((VG_TT_SIZE * VG_TT_LIMIT_PERCENT) / 100)
sewardjde4a1d02002-03-22 01:27:54 +000058
sewardjde4a1d02002-03-22 01:27:54 +000059
sewardj6c3769f2002-11-29 01:02:45 +000060/*------------------ TYPES ------------------*/
61
sewardj78210aa2002-12-01 02:55:46 +000062#define CODE_ALIGNMENT 4 /* alignment of TCEntries */
sewardj22854b92002-11-30 14:00:47 +000063#define CODE_ALIGN(a) (((a)+CODE_ALIGNMENT-1) & ~(CODE_ALIGNMENT-1))
64#define IS_ALIGNED(a) (((a) & (CODE_ALIGNMENT-1)) == 0)
65
sewardj6c3769f2002-11-29 01:02:45 +000066/* An entry in TC. Payload always is always padded out to a 4-aligned
67 quantity so that these structs are always word-aligned. */
68typedef
69 struct {
70 /* +0 */ Addr orig_addr;
71 /* +4 */ UShort orig_size;
72 /* +6 */ UShort trans_size;
sewardj22854b92002-11-30 14:00:47 +000073 /* +8 */ UShort jump_sites[VG_MAX_JUMPS];
74 /* +VG_CODE_OFFSET */ UChar payload[0];
sewardj6c3769f2002-11-29 01:02:45 +000075 }
76 TCEntry;
77
78/* An entry in TT. */
79typedef
80 struct {
81 Addr orig_addr;
82 TCEntry* tcentry;
83 }
84 TTEntry;
85
86/* Denotes an empty TT slot, when TTEntry.orig_addr holds this
87 value. */
88#define VG_TTE_EMPTY ((Addr)1)
89
90/* Denotes an empty TT slot, when TTEntry.orig_addr holds this
91 value. */
sewardjde4a1d02002-03-22 01:27:54 +000092#define VG_TTE_DELETED ((Addr)3)
93
sewardj6c3769f2002-11-29 01:02:45 +000094/* A bogus TCEntry which hopefully does not match code from any valid
95 address. This is what all VG_(tt_fast) entries are made to point
96 at when we want to invalidate it. */
97static const TCEntry vg_tc_bogus_TCEntry = { ((Addr)5), 0, 0 };
sewardjde4a1d02002-03-22 01:27:54 +000098
sewardjde4a1d02002-03-22 01:27:54 +000099
sewardj6c3769f2002-11-29 01:02:45 +0000100/*------------------ DECLS ------------------*/
101
102/* The translation cache sectors. These are NULL until allocated
103 dynamically. */
104static UChar* vg_tc[VG_TC_N_SECTORS];
105
106/* Count of bytes used in each sector of the TC. */
107static Int vg_tc_used[VG_TC_N_SECTORS];
108
109/* The age of each sector, so we can find the oldest. We just use the
110 global count of translations made when the sector was brought into
111 use. Doesn't matter if this mechanism gets confused (wraps around
112 4G) once in a while. */
113static Int vg_tc_age[VG_TC_N_SECTORS];
114
115/* The number of the sector currently being allocated in. */
116static Int vg_tc_current;
117
sewardjc0d8f682002-11-30 00:49:43 +0000118/* Count of number of translations, orig and new bytes in each sector.
119 For stats purposes only. */
120static Int vg_tc_stats_count[VG_TC_N_SECTORS];
121static Int vg_tc_stats_osize[VG_TC_N_SECTORS];
122static Int vg_tc_stats_tsize[VG_TC_N_SECTORS];
123
sewardj6c3769f2002-11-29 01:02:45 +0000124
125/*------------------ TRANSLATION TABLE ------------------*/
126
127/* The translation table. An array of VG_TT_SIZE TTEntrys. */
sewardjde4a1d02002-03-22 01:27:54 +0000128static TTEntry* vg_tt = NULL;
129
sewardj18d75132002-05-16 11:06:21 +0000130/* Count of non-empty TT entries. This includes deleted ones. */
sewardjde4a1d02002-03-22 01:27:54 +0000131static Int vg_tt_used = 0;
132
133/* Fast helper for the TT. A direct-mapped cache which holds a
134 pointer to a TT entry which may or may not be the correct one, but
135 which we hope usually is. This array is referred to directly from
136 vg_dispatch.S. */
sewardj6c3769f2002-11-29 01:02:45 +0000137Addr /* TCEntry*, really */ VG_(tt_fast)[VG_TT_FAST_SIZE];
sewardj8aef1192002-07-24 09:36:36 +0000138
sewardj22854b92002-11-30 14:00:47 +0000139static void for_each_tc(Int sector, void (*fn)(TCEntry *));
140
141
142/*------------------ T-CHAINING HELPERS ------------------*/
143
144static
145void for_each_jumpsite(TCEntry *tce, void (*fn)(Addr))
146{
147 Int i;
148 for(i = 0; i < VG_MAX_JUMPS; i++) {
149 Addr a;
150 UShort idx = tce->jump_sites[i];
151
152 if (idx == (UShort)-1)
153 continue;
154
155 a = (Addr)&tce->payload[idx];
156
157 (*fn)(a);
158 }
159}
160
161static inline
162void unchain_tce(TCEntry *tce)
163{
164 for_each_jumpsite(tce, VG_(unchain_jumpsite));
165}
166
167/* Unchain any jumps pointing to a sector we're about to free */
168static
169void unchain_sector(Int s, Addr base, UInt len)
170{
171 void unchain_site(Addr a) {
172 Addr jmp = VG_(get_jmp_dest)(a);
173 if (jmp >= base && jmp < (base+len))
174 VG_(unchain_jumpsite)(a);
175 }
176 void _unchain_tce(TCEntry *tce) {
177 for_each_jumpsite(tce, unchain_site);
178 }
179
180 for_each_tc(s, _unchain_tce);
181}
182
sewardjde4a1d02002-03-22 01:27:54 +0000183
sewardj6c3769f2002-11-29 01:02:45 +0000184/*------------------ TT HELPERS ------------------*/
185
sewardjc0d8f682002-11-30 00:49:43 +0000186static
187void pp_tt_tc_status ( Char* submsg )
188{
189 Int tc_used, s;
190 if (VG_(clo_verbosity) <= 2)
191 return;
192 tc_used = 0;
193 for (s = 0; s < VG_TC_N_SECTORS; s++)
194 tc_used += vg_tc_used[s];
195
196 VG_(message)(Vg_DebugMsg,
197 "%luk bbs: tt %d, tc %d, %s",
198 VG_(bbs_done) / 1000,
199 vg_tt_used, tc_used, submsg );
200}
201
sewardj6c3769f2002-11-29 01:02:45 +0000202/* Invalidate the tt_fast cache, for whatever reason, by pointing all
203 entries at vg_tc_bogus_TCEntry. */
204static
205void vg_invalidate_tt_fast( void )
206{
207 Int j;
208 for (j = 0; j < VG_TT_FAST_SIZE; j++)
209 VG_(tt_fast)[j] = (Addr)&vg_tc_bogus_TCEntry;
210}
211
212
213static
214void add_tt_entry ( TCEntry* tce )
215{
216 UInt i;
217 /* VG_(printf)("add_TT_entry orig_addr %p\n", tce->orig_addr); */
218 /* Hash to get initial probe point. */
219 i = ((UInt)(tce->orig_addr)) % VG_TT_SIZE;
220 while (True) {
221 if (vg_tt[i].orig_addr == tce->orig_addr)
222 VG_(core_panic)("add_TT_entry: duplicate");
223 if (vg_tt[i].orig_addr == VG_TTE_EMPTY)
224 break;
225 i++;
226 if (i == VG_TT_SIZE)
227 i = 0;
228 }
sewardj22854b92002-11-30 14:00:47 +0000229
sewardj6c3769f2002-11-29 01:02:45 +0000230 vg_tt[i].orig_addr = tce->orig_addr;
231 vg_tt[i].tcentry = tce;
232 vg_tt_used++;
233 /* sanity ... */
234 vg_assert(vg_tt_used < VG_TT_SIZE-1000);
235}
236
237
238/* Search TT to find the translated address of the supplied original,
239 or NULL if not found. This routine is used when we miss in
240 VG_(tt_fast).
241*/
242static __inline__
243TTEntry* search_tt ( Addr orig_addr )
244{
245 Int i;
246 /* Hash to get initial probe point. */
247 i = ((UInt)orig_addr) % VG_TT_SIZE;
248 while (True) {
249 if (vg_tt[i].orig_addr == orig_addr)
250 return &vg_tt[i];
251 if (vg_tt[i].orig_addr == VG_TTE_EMPTY)
252 return NULL;
253 i++;
254 if (i == VG_TT_SIZE) i = 0;
255 }
256}
257
258
259static
260void initialise_tt ( void )
261{
262 Int i;
263 vg_tt_used = 0;
264 for (i = 0; i < VG_TT_SIZE; i++) {
265 vg_tt[i].orig_addr = VG_TTE_EMPTY;
266 }
267 vg_invalidate_tt_fast();
268}
269
270
271static
272void rebuild_TT ( void )
273{
274 Int s;
sewardj6c3769f2002-11-29 01:02:45 +0000275
276 /* Throw away TT. */
277 initialise_tt();
278
279 /* Rebuild TT from the remaining quarters. */
280 for (s = 0; s < VG_TC_N_SECTORS; s++) {
sewardj22854b92002-11-30 14:00:47 +0000281 for_each_tc(s, add_tt_entry);
sewardj6c3769f2002-11-29 01:02:45 +0000282 }
sewardjc0d8f682002-11-30 00:49:43 +0000283 pp_tt_tc_status ( "after rebuild of TC" );
sewardj6c3769f2002-11-29 01:02:45 +0000284}
285
286
287/*------------------ TC HELPERS ------------------*/
288
sewardj22854b92002-11-30 14:00:47 +0000289static
290void for_each_tc(Int s, void (*fn)(TCEntry *))
291{
292 UChar *pc;
293 UChar *pc_lim;
294 TCEntry *tce;
295
296 pc = &(vg_tc[s][0]);
297 pc_lim = &(vg_tc[s][vg_tc_used[s]]);
298 while (True) {
299 if (pc >= pc_lim) break;
300 tce = (TCEntry*)pc;
301 pc += sizeof(TCEntry) + tce->trans_size;
302 if (tce->orig_addr != VG_TTE_DELETED)
303 (*fn)(tce);
304 }
305}
306
sewardj6c3769f2002-11-29 01:02:45 +0000307/* Find the oldest non-NULL, non-empty sector, or -1 if none such. */
308static
309Int find_oldest_sector ( void )
310{
311 Int oldest_age, oldest, i;
312 oldest_age = 1000 * 1000 * 1000;
313 oldest = -1;
314 for (i = 0; i < VG_TC_N_SECTORS; i++) {
315 if (vg_tc[i] == NULL)
316 continue;
317 if (vg_tc_used[i] == 0)
318 continue;
319 if (vg_tc_age[i] < oldest_age) {
320 oldest = i;
321 oldest_age = vg_tc_age[i];
322 }
323 }
324 return oldest;
325}
326
327
328/* Discard the oldest sector, if any such exists. */
329static
330void discard_oldest_sector ( void )
331{
sewardjc0d8f682002-11-30 00:49:43 +0000332 Char msg[100];
sewardj6c3769f2002-11-29 01:02:45 +0000333 Int s = find_oldest_sector();
334 if (s != -1) {
sewardj22854b92002-11-30 14:00:47 +0000335 Int i;
336
sewardj6c3769f2002-11-29 01:02:45 +0000337 vg_assert(s >= 0 && s < VG_TC_N_SECTORS);
sewardjc0d8f682002-11-30 00:49:43 +0000338 VG_(sprintf)(msg, "before discard of sector %d (%d bytes)",
339 s, vg_tc_used[s]);
sewardj22854b92002-11-30 14:00:47 +0000340
341 for(i = 0; i < VG_TC_N_SECTORS; i++) {
342 if (i != s && vg_tc[i] != NULL)
343 unchain_sector(i, (Addr)vg_tc[s], vg_tc_used[s]);
344 }
345
sewardjc0d8f682002-11-30 00:49:43 +0000346 pp_tt_tc_status ( msg );
347 VG_(overall_out_count) += vg_tc_stats_count[s];
348 VG_(overall_out_osize) += vg_tc_stats_osize[s];
349 VG_(overall_out_tsize) += vg_tc_stats_tsize[s];
sewardj6c3769f2002-11-29 01:02:45 +0000350 vg_tc_used[s] = 0;
sewardjc0d8f682002-11-30 00:49:43 +0000351 vg_tc_stats_count[s] = 0;
352 vg_tc_stats_osize[s] = 0;
353 vg_tc_stats_tsize[s] = 0;
354 VG_(number_of_tc_discards) ++;
sewardj6c3769f2002-11-29 01:02:45 +0000355 }
356}
357
358
359/* Find an empty sector and bring it into use. If there isn't one,
360 try and allocate one. If that fails, return -1. */
361static
362Int maybe_commission_sector ( void )
363{
sewardjc0d8f682002-11-30 00:49:43 +0000364 Char msg[100];
365 Int s;
sewardj6c3769f2002-11-29 01:02:45 +0000366 for (s = 0; s < VG_TC_N_SECTORS; s++) {
367 if (vg_tc[s] != NULL && vg_tc_used[s] == 0) {
368 vg_tc_age[s] = VG_(overall_in_count);
sewardjc0d8f682002-11-30 00:49:43 +0000369 VG_(sprintf)(msg, "after commission of sector %d "
370 "at time %d",
371 s, vg_tc_age[s]);
372 pp_tt_tc_status ( msg );
sewardj6c3769f2002-11-29 01:02:45 +0000373# ifdef DEBUG_TRANSTAB
374 VG_(sanity_check_tc_tt)();
375# endif
376 return s;
377 }
378 }
379 for (s = 0; s < VG_TC_N_SECTORS; s++) {
380 if (vg_tc[s] == NULL) {
381 vg_tc[s] = VG_(get_memory_from_mmap)
sewardjc0d8f682002-11-30 00:49:43 +0000382 ( vg_tc_sector_szB, "trans-cache(sector)" );
sewardj6c3769f2002-11-29 01:02:45 +0000383 vg_tc_used[s] = 0;
sewardjc0d8f682002-11-30 00:49:43 +0000384 VG_(sprintf)(msg, "after allocation of sector %d "
385 "(size %d)",
386 s, vg_tc_sector_szB );
387 pp_tt_tc_status ( msg );
sewardj6c3769f2002-11-29 01:02:45 +0000388 return maybe_commission_sector();
389 }
390 }
391 return -1;
392}
393
sewardj6c3769f2002-11-29 01:02:45 +0000394
395static
396UChar* allocate ( Int nBytes )
397{
398 Int i;
399
sewardj22854b92002-11-30 14:00:47 +0000400 vg_assert(IS_ALIGNED(nBytes));
sewardj6c3769f2002-11-29 01:02:45 +0000401
402 /* Ensure the TT is still OK. */
403 while (vg_tt_used >= VG_TT_LIMIT) {
404 (void)discard_oldest_sector();
405 rebuild_TT();
406 vg_assert(vg_tt_used < VG_TT_LIMIT);
407 }
408
409 /* Can we get it into the current sector? */
410 if (vg_tc_current >= 0
411 && vg_tc_current < VG_TC_N_SECTORS
412 && vg_tc[vg_tc_current] != NULL
sewardjc0d8f682002-11-30 00:49:43 +0000413 && vg_tc_used[vg_tc_current] + nBytes <= vg_tc_sector_szB) {
sewardj6c3769f2002-11-29 01:02:45 +0000414 /* Yes. */
415 UChar* p = &(vg_tc[vg_tc_current][ vg_tc_used[vg_tc_current] ]);
416 vg_tc_used[vg_tc_current] += nBytes;
417 return p;
418 }
419
420 /* Perhaps we can bring a new sector into use, for the first
421 time. */
422 vg_tc_current = maybe_commission_sector();
423 if (vg_tc_current >= 0 && vg_tc_current < VG_TC_N_SECTORS)
424 return allocate(nBytes);
425
426 /* That didn't work. We'll have to dump the oldest. We take the
427 opportunity to dump the N oldest at once. */
428 for (i = 0; i < 1; i++)
429 (void)discard_oldest_sector();
430
431 rebuild_TT();
432 vg_tc_current = maybe_commission_sector();
433 vg_assert(vg_tc_current >= 0 && vg_tc_current < VG_TC_N_SECTORS);
434# ifdef DEBUG_TRANSTAB
435 VG_(sanity_check_tc_tt)();
436# endif
437
438 return allocate(nBytes);
439}
sewardjde4a1d02002-03-22 01:27:54 +0000440
441
442/* Just so these counts can be queried without making them globally
443 visible. */
444void VG_(get_tt_tc_used) ( UInt* tt_used, UInt* tc_used )
445{
sewardj6c3769f2002-11-29 01:02:45 +0000446 Int s;
sewardjde4a1d02002-03-22 01:27:54 +0000447 *tt_used = vg_tt_used;
sewardj6c3769f2002-11-29 01:02:45 +0000448 *tc_used = 0;
449 for (s = 0; s < VG_TC_N_SECTORS; s++)
450 *tc_used += vg_tc_used[s];
sewardjde4a1d02002-03-22 01:27:54 +0000451}
452
453
454/* Do a sanity check on TT/TC.
455*/
456void VG_(sanity_check_tc_tt) ( void )
457{
sewardjc0d8f682002-11-30 00:49:43 +0000458 Int i, s;
459 TTEntry* tte;
460 TCEntry* tce;
461 /* Checks:
462 - Each TT entry points to a valid and corresponding TC entry.
sewardj6c3769f2002-11-29 01:02:45 +0000463 */
464 for (i = 0; i < VG_TT_SIZE; i++) {
465 tte = &vg_tt[i];
466 /* empty slots are harmless. */
467 if (tte->orig_addr == VG_TTE_EMPTY) continue;
468 /* all others should agree with the TC entry. */
469 tce = tte->tcentry;
470 vg_assert(IS_ALIGNED4_ADDR(tce));
471 /* does this point into a valid TC sector? */
472 for (s = 0; s < VG_TC_N_SECTORS; s++)
473 if (vg_tc[s] != NULL
474 && ((Addr)tce) >= (Addr)&vg_tc[s][0]
475 && ((Addr)tce) < (Addr)&vg_tc[s][ vg_tc_used[s] ])
476 break;
477 vg_assert(s < VG_TC_N_SECTORS);
478 /* It should agree with the TC entry on the orig_addr. This may
479 be VG_TTE_DELETED, or a real orig addr. */
480 vg_assert(tte->orig_addr == tce->orig_addr);
481 }
sewardjde4a1d02002-03-22 01:27:54 +0000482}
483
484
485/* Add this already-filled-in entry to the TT. Assumes that the
486 relevant code chunk has been placed in TC, along with a dummy back
sewardjc0d8f682002-11-30 00:49:43 +0000487 pointer, which is inserted here.
sewardjde4a1d02002-03-22 01:27:54 +0000488*/
sewardjc0d8f682002-11-30 00:49:43 +0000489void VG_(add_to_trans_tab) ( Addr orig_addr, Int orig_size,
sewardj22854b92002-11-30 14:00:47 +0000490 Addr trans_addr, Int trans_size,
491 UShort jumps[VG_MAX_JUMPS])
sewardjde4a1d02002-03-22 01:27:54 +0000492{
sewardj6c3769f2002-11-29 01:02:45 +0000493 Int i, nBytes, trans_size_aligned;
494 TCEntry* tce;
sewardjde4a1d02002-03-22 01:27:54 +0000495 /*
496 VG_(printf)("add_to_trans_tab(%d) %x %d %x %d\n",
497 vg_tt_used, tte->orig_addr, tte->orig_size,
498 tte->trans_addr, tte->trans_size);
499 */
sewardj6c3769f2002-11-29 01:02:45 +0000500
sewardj22854b92002-11-30 14:00:47 +0000501 vg_assert(offsetof(TCEntry, payload) == VG_CODE_OFFSET);
502
sewardj6c3769f2002-11-29 01:02:45 +0000503 /* figure out how many bytes we require. */
sewardj22854b92002-11-30 14:00:47 +0000504 nBytes = CODE_ALIGN(trans_size + sizeof(TCEntry));
505 trans_size_aligned = nBytes-sizeof(TCEntry);
506 vg_assert(IS_ALIGNED(nBytes));
sewardj6c3769f2002-11-29 01:02:45 +0000507
508 tce = (TCEntry*)allocate(nBytes);
sewardj78210aa2002-12-01 02:55:46 +0000509 /*
510 VG_(printf)("allocate returned %p (code start %p)\n",
511 tce, &tce->payload[0]);
512 */
sewardjc0d8f682002-11-30 00:49:43 +0000513 vg_assert(vg_tc_current >= 0 && vg_tc_current < VG_TC_N_SECTORS);
514
sewardj6c3769f2002-11-29 01:02:45 +0000515 tce->orig_addr = orig_addr;
516 tce->orig_size = (UShort)orig_size; /* what's the point of storing this? */
517 tce->trans_size = (UShort)trans_size_aligned;
sewardj22854b92002-11-30 14:00:47 +0000518 for (i = 0; i < VG_MAX_JUMPS; i++) {
519 tce->jump_sites[i] = jumps[i];
520 }
sewardj6c3769f2002-11-29 01:02:45 +0000521 for (i = 0; i < trans_size; i++) {
522 tce->payload[i] = ((UChar*)trans_addr)[i];
sewardjde4a1d02002-03-22 01:27:54 +0000523 }
sewardj22854b92002-11-30 14:00:47 +0000524
525 unchain_tce(tce);
sewardj6c3769f2002-11-29 01:02:45 +0000526 add_tt_entry(tce);
sewardjc0d8f682002-11-30 00:49:43 +0000527
528 /* Update stats. */
529 VG_(overall_in_count) ++;
530 VG_(overall_in_osize) += orig_size;
531 VG_(overall_in_tsize) += trans_size;
532
533 vg_tc_stats_count[vg_tc_current] ++;
534 vg_tc_stats_osize[vg_tc_current] += orig_size;
535 vg_tc_stats_tsize[vg_tc_current] += trans_size;
sewardjde4a1d02002-03-22 01:27:54 +0000536}
537
538
539/* Find the translation address for a given (original) code address.
540 If found, update VG_(tt_fast) so subsequent lookups are fast. If
541 no translation can be found, return zero. This routine is (the
542 only one) called from vg_run_innerloop. */
543Addr VG_(search_transtab) ( Addr original_addr )
544{
545 TTEntry* tte;
546 VGP_PUSHCC(VgpSlowFindT);
sewardj6c3769f2002-11-29 01:02:45 +0000547 tte = search_tt ( original_addr );
sewardjde4a1d02002-03-22 01:27:54 +0000548 if (tte == NULL) {
549 /* We didn't find it. vg_run_innerloop will have to request a
550 translation. */
njn25e49d8e72002-09-23 09:36:25 +0000551 VGP_POPCC(VgpSlowFindT);
sewardjde4a1d02002-03-22 01:27:54 +0000552 return (Addr)0;
553 } else {
sewardj1f086892002-12-15 01:47:05 +0000554 /* Found it. Put the search result into the fast cache now. */
sewardjde4a1d02002-03-22 01:27:54 +0000555 UInt cno = (UInt)original_addr & VG_TT_FAST_MASK;
sewardj6c3769f2002-11-29 01:02:45 +0000556 VG_(tt_fast)[cno] = (Addr)(tte->tcentry);
sewardjde4a1d02002-03-22 01:27:54 +0000557 VG_(tt_fast_misses)++;
njn25e49d8e72002-09-23 09:36:25 +0000558 VGP_POPCC(VgpSlowFindT);
sewardj6c3769f2002-11-29 01:02:45 +0000559 return (Addr)&(tte->tcentry->payload[0]);
sewardjde4a1d02002-03-22 01:27:54 +0000560 }
561}
562
563
sewardj18d75132002-05-16 11:06:21 +0000564/* Invalidate translations of original code [start .. start + range - 1].
565 This is slow, so you *really* don't want to call it very often.
sewardjde4a1d02002-03-22 01:27:54 +0000566*/
sewardj18d75132002-05-16 11:06:21 +0000567void VG_(invalidate_translations) ( Addr start, UInt range )
sewardjde4a1d02002-03-22 01:27:54 +0000568{
sewardj6c3769f2002-11-29 01:02:45 +0000569 Addr i_start, i_end, o_start, o_end;
570 UInt out_count, out_osize, out_tsize;
571 Int i;
572 TCEntry* tce;
sewardj18d75132002-05-16 11:06:21 +0000573# ifdef DEBUG_TRANSTAB
574 VG_(sanity_check_tc_tt)();
sewardjde4a1d02002-03-22 01:27:54 +0000575# endif
sewardj18d75132002-05-16 11:06:21 +0000576 i_start = start;
577 i_end = start + range - 1;
578 out_count = out_osize = out_tsize = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000579
sewardj18d75132002-05-16 11:06:21 +0000580 for (i = 0; i < VG_TT_SIZE; i++) {
581 if (vg_tt[i].orig_addr == VG_TTE_EMPTY
582 || vg_tt[i].orig_addr == VG_TTE_DELETED) continue;
sewardj6c3769f2002-11-29 01:02:45 +0000583 tce = vg_tt[i].tcentry;
584 o_start = tce->orig_addr;
585 o_end = o_start + tce->trans_size - 1;
sewardj18d75132002-05-16 11:06:21 +0000586 if (o_end < i_start || o_start > i_end)
587 continue;
njn25e49d8e72002-09-23 09:36:25 +0000588
589 if (VG_(needs).basic_block_discards)
sewardj6c3769f2002-11-29 01:02:45 +0000590 SK_(discard_basic_block_info)( tce->orig_addr,
591 tce->orig_size );
njn25e49d8e72002-09-23 09:36:25 +0000592
sewardj18d75132002-05-16 11:06:21 +0000593 vg_tt[i].orig_addr = VG_TTE_DELETED;
sewardj6c3769f2002-11-29 01:02:45 +0000594 tce->orig_addr = VG_TTE_DELETED;
sewardj18d75132002-05-16 11:06:21 +0000595 VG_(overall_out_count) ++;
sewardj6c3769f2002-11-29 01:02:45 +0000596 VG_(overall_out_osize) += tce->orig_size;
597 VG_(overall_out_tsize) += tce->trans_size;
sewardj18d75132002-05-16 11:06:21 +0000598 out_count ++;
sewardj6c3769f2002-11-29 01:02:45 +0000599 out_osize += tce->orig_size;
600 out_tsize += tce->trans_size;
sewardjde4a1d02002-03-22 01:27:54 +0000601 }
sewardjde4a1d02002-03-22 01:27:54 +0000602
sewardj18d75132002-05-16 11:06:21 +0000603 if (out_count > 0) {
sewardj6c3769f2002-11-29 01:02:45 +0000604 vg_invalidate_tt_fast();
sewardj18d75132002-05-16 11:06:21 +0000605 VG_(sanity_check_tc_tt)();
606# ifdef DEBUG_TRANSTAB
607 { Addr aa;
608 for (aa = i_start; aa <= i_end; aa++)
sewardj6c3769f2002-11-29 01:02:45 +0000609 vg_assert(search_tt ( aa ) == NULL);
sewardjde4a1d02002-03-22 01:27:54 +0000610 }
sewardj18d75132002-05-16 11:06:21 +0000611# endif
sewardjde4a1d02002-03-22 01:27:54 +0000612 }
613
sewardjc0d8f682002-11-30 00:49:43 +0000614 if (VG_(clo_verbosity) > 2)
sewardj18d75132002-05-16 11:06:21 +0000615 VG_(message)(Vg_UserMsg,
616 "discard %d (%d -> %d) translations in range %p .. %p",
617 out_count, out_osize, out_tsize, i_start, i_end );
sewardjde4a1d02002-03-22 01:27:54 +0000618}
619
620
621/*------------------------------------------------------------*/
622/*--- Initialisation. ---*/
623/*------------------------------------------------------------*/
624
sewardjc0d8f682002-11-30 00:49:43 +0000625void VG_(init_tt_tc) ( void )
626{
627 Int s;
628
sewardj22854b92002-11-30 14:00:47 +0000629 /* Otherwise we wind up with non-32-bit-aligned code in
630 TCEntries. */
631 vg_assert((VG_MAX_JUMPS % 2) == 0);
632
sewardjc0d8f682002-11-30 00:49:43 +0000633 /* Figure out how big each sector should be. */
634 vg_tc_sector_szB
635 = (VG_TT_LIMIT /* max TT entries we expect */
sewardj78210aa2002-12-01 02:55:46 +0000636 * (VG_(details).avg_translation_sizeB
637 + sizeof(TCEntry)
638 + (CODE_ALIGNMENT/2) /* avg alignment loss */)
639 )
sewardjc0d8f682002-11-30 00:49:43 +0000640 / VG_TC_N_SECTORS;
641 /* Ensure the calculated value is not way crazy. */
642 vg_assert(vg_tc_sector_szB >= 200000);
643 vg_assert(vg_tc_sector_szB <= 6000000);
644
645 for (s = 0; s < VG_TC_N_SECTORS; s++) {
646 vg_tc[s] = NULL;
647 vg_tc_used[s] = 0;
648 vg_tc_age[s] = 0;
649 vg_tc_stats_count[s] = 0;
650 vg_tc_stats_osize[s] = 0;
651 vg_tc_stats_tsize[s] = 0;
652 }
653 vg_tc_current = 0;
654
655 vg_tt = VG_(get_memory_from_mmap) ( VG_TT_SIZE * sizeof(TTEntry),
656 "trans-table" );
657 /* The main translation table is empty. */
658 initialise_tt();
659
660 if (VG_(clo_verbosity) > 2) {
661 VG_(message)(Vg_DebugMsg,
662 "Translation Cache: using %d sectors of %d bytes each",
663 VG_TC_N_SECTORS, vg_tc_sector_szB );
664 VG_(message)(Vg_DebugMsg,
665 "Translation Table: %d total entries, max occupancy %d (%d%%)",
666 VG_TT_SIZE, VG_TT_LIMIT, VG_TT_LIMIT_PERCENT );
667 }
668
669# ifdef DEBUG_TRANSTAB
670 VG_(sanity_check_tc_tt)();
671# endif
672}
673
sewardjde4a1d02002-03-22 01:27:54 +0000674/*--------------------------------------------------------------------*/
675/*--- end vg_transtab.c ---*/
676/*--------------------------------------------------------------------*/