blob: a6e15b305371234a3098055d634d3380be952c7e [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/*
8 This file is part of Valgrind, an x86 protected-mode emulator
9 designed for debugging and profiling binaries on x86-Unixes.
10
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
29 The GNU General Public License is contained in the file LICENSE.
30*/
31
32#include "vg_include.h"
33#include "vg_constants.h"
34
sewardj18d75132002-05-16 11:06:21 +000035/* #define DEBUG_TRANSTAB */
36
sewardjde4a1d02002-03-22 01:27:54 +000037
38/*------------------------------------------------------------*/
39/*--- Management of the LRU-based translation table+cache. ---*/
40/*------------------------------------------------------------*/
41
42/* These sizes were set up so as to be able to debug large KDE 3
43 applications (are there any small ones?) without excessive amounts
44 of code retranslation. */
45
46/* Size of the translation cache, in bytes. */
sewardj18d75132002-05-16 11:06:21 +000047#define VG_TC_SIZE /*1000000*/ /*16000000*/ 32000000 /*40000000*/
sewardjde4a1d02002-03-22 01:27:54 +000048
49/* Do a LRU pass when the translation cache becomes this full. */
sewardjec055642002-05-03 18:59:21 +000050#define VG_TC_LIMIT_PERCENT 98
sewardjde4a1d02002-03-22 01:27:54 +000051
52/* When doing an LRU pass, reduce TC fullness to this level. */
53#define VG_TC_TARGET_PERCENT 85
54
55/* Number of entries in the translation table. This must be a prime
56 number in order to make the hashing work properly. */
sewardj18d75132002-05-16 11:06:21 +000057#define VG_TT_SIZE /*5281*/ /*100129*/ 200191 /*250829*/
sewardjde4a1d02002-03-22 01:27:54 +000058
59/* Do an LRU pass when the translation table becomes this full. */
60#define VG_TT_LIMIT_PERCENT /*67*/ 80
61
62/* When doing an LRU pass, reduce TT fullness to this level. */
63#define VG_TT_TARGET_PERCENT /*60*/ 70
64
65/* The number of age steps we track. 0 means the current epoch,
66 N_EPOCHS-1 means used the epoch N_EPOCHS-1 or more ago. */
sewardjac680282002-03-25 02:02:52 +000067#define VG_N_EPOCHS /*2000*/ /*4000*/ 20000
sewardjde4a1d02002-03-22 01:27:54 +000068
sewardj18d75132002-05-16 11:06:21 +000069/* This TT entry is empty. There is no associated TC storage. */
sewardjde4a1d02002-03-22 01:27:54 +000070#define VG_TTE_EMPTY ((Addr)1)
sewardj18d75132002-05-16 11:06:21 +000071/* This TT entry has been deleted, in the sense that it does not
72 contribute to the orig->trans mapping. However, the ex-translation
73 it points at still occupies space in TC. This slot cannot be
74 re-used without doing an LRU pass. */
sewardjde4a1d02002-03-22 01:27:54 +000075#define VG_TTE_DELETED ((Addr)3)
76
77/* The TC. This used to be statically allocated, but that forces many
78 SecMap arrays to be pointlessly allocated at startup, bloating the
79 process size by about 22M and making startup slow. So now we
80 dynamically allocate it at startup time.
81 was: static UChar vg_tc[VG_TC_SIZE];
82*/
83static UChar* vg_tc = NULL;
84
sewardj18d75132002-05-16 11:06:21 +000085/* Count of bytes used in the TC. This includes those pointed to from
86 VG_TTE_DELETED entries. */
sewardjde4a1d02002-03-22 01:27:54 +000087static Int vg_tc_used = 0;
88
89/* The TT. Like TC, for the same reason, is dynamically allocated at
90 startup.
91 was: static TTEntry vg_tt[VG_TT_SIZE];
92*/
93static TTEntry* vg_tt = NULL;
94
sewardj18d75132002-05-16 11:06:21 +000095/* Count of non-empty TT entries. This includes deleted ones. */
sewardjde4a1d02002-03-22 01:27:54 +000096static Int vg_tt_used = 0;
97
98/* Fast helper for the TT. A direct-mapped cache which holds a
99 pointer to a TT entry which may or may not be the correct one, but
100 which we hope usually is. This array is referred to directly from
101 vg_dispatch.S. */
102Addr VG_(tt_fast)[VG_TT_FAST_SIZE];
103
104/* For reading/writing the misaligned TT-index word at immediately
105 preceding every translation in TC. */
sewardj8aef1192002-07-24 09:36:36 +0000106#if 0
107 /* Big sigh. However reasonable this seems, there are those who
108 set AC in %EFLAGS (Alignment Check) to 1, causing bus errors. A
109 proper solution is for valgrind to properly virtualise AC, like
110 the other flags (DOSZACP). The current cheap hack simply avoids
111 all misaligned accesses, so valgrind doesn't fault even if AC is
112 set. */
113# define VG_READ_MISALIGNED_WORD(aaa) (*((UInt*)(aaa)))
114# define VG_WRITE_MISALIGNED_WORD(aaa,vvv) *((UInt*)(aaa)) = ((UInt)(vvv))
115#else
116 static __inline__
117 UInt VG_READ_MISALIGNED_WORD ( Addr aaa )
118 {
119 UInt w = 0;
120 UChar* p = (UChar*)aaa;
121 w = 0xFF & ((UInt)(p[3]));
122 w = (w << 8) | (0xFF & ((UInt)(p[2])));
123 w = (w << 8) | (0xFF & ((UInt)(p[1])));
124 w = (w << 8) | (0xFF & ((UInt)(p[0])));
125 return w;
126 }
127
128 static __inline__
129 void VG_WRITE_MISALIGNED_WORD ( Addr aaa, UInt vvv )
130 {
131 UChar* p = (UChar*)aaa;
132 p[0] = vvv & 0xFF;
133 p[1] = (vvv >> 8) & 0xFF;
134 p[2] = (vvv >> 16) & 0xFF;
135 p[3] = (vvv >> 24) & 0xFF;
136 }
137#endif
138
sewardjde4a1d02002-03-22 01:27:54 +0000139
140/* Used for figuring out an age threshold for translations. */
141static Int vg_bytes_in_epoch[VG_N_EPOCHS];
142static Int vg_entries_in_epoch[VG_N_EPOCHS];
143
144
145/* Just so these counts can be queried without making them globally
146 visible. */
147void VG_(get_tt_tc_used) ( UInt* tt_used, UInt* tc_used )
148{
149 *tt_used = vg_tt_used;
150 *tc_used = vg_tc_used;
151}
152
153
154/* Do the LRU thing on TT/TC, clearing them back to the target limits
155 if they are over the threshold limits.
156*/
157void VG_(maybe_do_lru_pass) ( void )
158{
159 Int i, j, r, w, thresh, ttno;
160 TTEntry* tte;
161
sewardj215e7f02002-05-02 03:47:01 +0000162 const Int tc_limit = (Int)(((double)VG_TC_SIZE * (double)VG_TC_LIMIT_PERCENT)
163 / (double)100.0);
164 const Int tt_limit = (Int)(((double)VG_TT_SIZE * (double)VG_TT_LIMIT_PERCENT)
165 / (double)100.0);
166 const Int tc_target = (Int)(((double)VG_TC_SIZE * (double)VG_TC_TARGET_PERCENT)
167 / (double)100.0);
168 const Int tt_target = (Int)(((double)VG_TT_SIZE * (double)VG_TT_TARGET_PERCENT)
169 / (double)100.0);
sewardjde4a1d02002-03-22 01:27:54 +0000170
171 /* Decide quickly if we need to do an LRU pass ? */
172 if (vg_tc_used <= tc_limit && vg_tt_used <= tt_limit)
173 return;
174
sewardj18d75132002-05-16 11:06:21 +0000175# ifdef DEBUG_TRANSTAB
176 VG_(sanity_check_tc_tt)();
177# endif
178
sewardjde4a1d02002-03-22 01:27:54 +0000179 VGP_PUSHCC(VgpDoLRU);
180 /*
181 VG_(printf)(
182 "limits: tc_limit %d, tt_limit %d, tc_target %d, tt_target %d\n",
183 tc_limit, tt_limit, tc_target, tt_target);
184 */
185
186 if (VG_(clo_verbosity) > 2)
187 VG_(printf)(" pre-LRU: tc %d (target %d), tt %d (target %d)\n",
188 vg_tc_used, tc_target, vg_tt_used, tt_target);
189
190 /* Yes we do. Figure out what threshold age is required in order to
191 shrink both the TC and TT occupancy below TC_TARGET_PERCENT and
192 TT_TARGET_PERCENT respectively. */
193
194 VG_(number_of_lrus)++;
195
196 /* Count the number of TC bytes and TT entries in each epoch. */
197 for (i = 0; i < VG_N_EPOCHS; i++)
198 vg_bytes_in_epoch[i] = vg_entries_in_epoch[i] = 0;
199
200 for (i = 0; i < VG_TT_SIZE; i++) {
sewardj18d75132002-05-16 11:06:21 +0000201 if (vg_tt[i].orig_addr == VG_TTE_EMPTY
202 || vg_tt[i].orig_addr == VG_TTE_DELETED)
203 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000204 j = vg_tt[i].mru_epoch;
205 vg_assert(j <= VG_(current_epoch));
206 j = VG_(current_epoch) - j;
207 if (j >= VG_N_EPOCHS) j = VG_N_EPOCHS-1;
208 vg_assert(0 <= j && j < VG_N_EPOCHS);
209 /* Greater j now means older. */
210 vg_entries_in_epoch[j]++;
211 vg_bytes_in_epoch[j] += 4+vg_tt[i].trans_size;
212 }
213
214 /*
215 for (i = 0; i < VG_N_EPOCHS; i++)
216 VG_(printf)("epoch %d: ents %d, bytes %d\n",
217 i, vg_entries_in_epoch[i], vg_bytes_in_epoch[i]);
218 */
219
220 /* Cumulatise. Make vg_{bytes,entries}_in_epoch[n] contain the
221 counts for itself and all younger epochs. */
222 for (i = 1; i < VG_N_EPOCHS; i++) {
223 vg_entries_in_epoch[i] += vg_entries_in_epoch[i-1];
224 vg_bytes_in_epoch[i] += vg_bytes_in_epoch[i-1];
225 }
226
227 for (thresh = 0; thresh < VG_N_EPOCHS; thresh++) {
228 if (vg_entries_in_epoch[thresh] > tt_target
229 || vg_bytes_in_epoch[thresh] >= tc_target)
230 break;
231 }
232
233 if (VG_(clo_verbosity) > 2)
234 VG_(printf)(
235 " LRU: discard translations %d or more epochs since last use\n",
236 thresh
237 );
238
239 thresh = VG_(current_epoch) - thresh;
240
241 /* Ok, so we will hit our targets if we retain all entries most
242 recently used at most thresh epochs ago. Traverse the TT and
243 mark such entries as deleted. */
244 for (i = 0; i < VG_TT_SIZE; i++) {
sewardj18d75132002-05-16 11:06:21 +0000245 if (vg_tt[i].orig_addr == VG_TTE_EMPTY
246 || vg_tt[i].orig_addr == VG_TTE_DELETED)
247 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000248 if (vg_tt[i].mru_epoch <= thresh) {
249 vg_tt[i].orig_addr = VG_TTE_DELETED;
sewardjde4a1d02002-03-22 01:27:54 +0000250 VG_(this_epoch_out_count) ++;
251 VG_(this_epoch_out_osize) += vg_tt[i].orig_size;
252 VG_(this_epoch_out_tsize) += vg_tt[i].trans_size;
253 VG_(overall_out_count) ++;
254 VG_(overall_out_osize) += vg_tt[i].orig_size;
255 VG_(overall_out_tsize) += vg_tt[i].trans_size;
256 }
257 }
258
sewardjde4a1d02002-03-22 01:27:54 +0000259 /* Now compact the TC, sliding live entries downwards to fill spaces
260 left by deleted entries. In this loop, r is the offset in TC of
261 the current translation under consideration, and w is the next
262 allocation point. */
263 r = w = 0;
264 while (True) {
265 if (r >= vg_tc_used) break;
266 /* The first four bytes of every translation contain the index
267 of its TT entry. The TT entry's .trans_addr field points at
268 the start of the code proper, not at this 4-byte index, so
269 that we don't constantly have to keep adding 4 in the main
270 lookup/dispatch loop. */
sewardj8aef1192002-07-24 09:36:36 +0000271
272 ttno = VG_READ_MISALIGNED_WORD((Addr)(&vg_tc[r]));
sewardjde4a1d02002-03-22 01:27:54 +0000273 vg_assert(ttno >= 0 && ttno < VG_TT_SIZE);
274 tte = & vg_tt[ ttno ];
275 vg_assert(tte->orig_addr != VG_TTE_EMPTY);
276 if (tte->orig_addr != VG_TTE_DELETED) {
277 /* We want to keep this one alive. */
278 /* Sanity check the pointer back to TC. */
279 vg_assert(tte->trans_addr == (Addr)&vg_tc[r+4]);
280 for (i = 0; i < 4+tte->trans_size; i++)
281 vg_tc[w+i] = vg_tc[r+i];
282 tte->trans_addr = (Addr)&vg_tc[w+4];
283 w += 4+tte->trans_size;
sewardj18d75132002-05-16 11:06:21 +0000284 } else {
285 tte->orig_addr = VG_TTE_EMPTY;
286 vg_tt_used--;
sewardjde4a1d02002-03-22 01:27:54 +0000287 }
288 r += 4+tte->trans_size;
289 }
290 /* should have traversed an exact number of translations, with no
291 slop at the end. */
292 vg_assert(w <= r);
293 vg_assert(r == vg_tc_used);
294 vg_assert(w <= r);
295 vg_assert(w <= tc_target);
296 vg_tc_used = w;
297
sewardj18d75132002-05-16 11:06:21 +0000298 vg_assert(vg_tt_used >= 0);
299 vg_assert(vg_tt_used <= tt_target);
300
sewardjde4a1d02002-03-22 01:27:54 +0000301 /* Invalidate the fast cache, since it is now out of date. It will get
302 reconstructed incrementally when the client resumes. */
303 VG_(invalidate_tt_fast)();
304
305 if (VG_(clo_verbosity) > 2)
306 VG_(printf)("post-LRU: tc %d (target %d), tt %d (target %d)\n",
307 vg_tc_used, tc_target, vg_tt_used, tt_target);
308
309 if (VG_(clo_verbosity) > 1)
310 VG_(message)(Vg_UserMsg,
311 "epoch %d (bb %luk): thresh %d, "
312 "out %d (%dk -> %dk), new TT %d, TC %dk",
313 VG_(current_epoch),
314 VG_(bbs_done) / 1000,
315 VG_(current_epoch) - thresh,
316 VG_(this_epoch_out_count),
317 VG_(this_epoch_out_osize) / 1000,
318 VG_(this_epoch_out_tsize) / 1000,
319 vg_tt_used, vg_tc_used / 1000
320 );
321
322 /* Reconstruct the SMC detection structures. */
sewardj18d75132002-05-16 11:06:21 +0000323# ifdef DEBUG_TRANSTAB
324 for (i = 0; i < VG_TT_SIZE; i++)
325 vg_assert(vg_tt[i].orig_addr != VG_TTE_DELETED);
326# endif
327 VG_(sanity_check_tc_tt)();
sewardjde4a1d02002-03-22 01:27:54 +0000328
329 VGP_POPCC;
330}
331
332
333/* Do a sanity check on TT/TC.
334*/
335void VG_(sanity_check_tc_tt) ( void )
336{
337 Int i, counted_entries, counted_bytes;
338 TTEntry* tte;
339 counted_entries = 0;
340 counted_bytes = 0;
341 for (i = 0; i < VG_TT_SIZE; i++) {
342 tte = &vg_tt[i];
343 if (tte->orig_addr == VG_TTE_EMPTY) continue;
sewardjde4a1d02002-03-22 01:27:54 +0000344 vg_assert(tte->mru_epoch >= 0);
345 vg_assert(tte->mru_epoch <= VG_(current_epoch));
346 counted_entries++;
347 counted_bytes += 4+tte->trans_size;
348 vg_assert(tte->trans_addr >= (Addr)&vg_tc[4]);
349 vg_assert(tte->trans_addr < (Addr)&vg_tc[vg_tc_used]);
350 vg_assert(VG_READ_MISALIGNED_WORD(tte->trans_addr-4) == i);
351 }
352 vg_assert(counted_entries == vg_tt_used);
353 vg_assert(counted_bytes == vg_tc_used);
354}
355
356
357/* Add this already-filled-in entry to the TT. Assumes that the
358 relevant code chunk has been placed in TC, along with a dummy back
359 pointer, which is inserted here.
360*/
361extern void VG_(add_to_trans_tab) ( TTEntry* tte )
362{
363 Int i;
364 /*
365 VG_(printf)("add_to_trans_tab(%d) %x %d %x %d\n",
366 vg_tt_used, tte->orig_addr, tte->orig_size,
367 tte->trans_addr, tte->trans_size);
368 */
369 vg_assert(tte->orig_addr != VG_TTE_DELETED
370 && tte->orig_addr != VG_TTE_EMPTY);
371 /* Hash to get initial probe point. */
372 i = ((UInt)(tte->orig_addr)) % VG_TT_SIZE;
373 while (True) {
374 if (vg_tt[i].orig_addr == tte->orig_addr)
375 VG_(panic)("add_to_trans_tab: duplicate");
sewardj18d75132002-05-16 11:06:21 +0000376 if (vg_tt[i].orig_addr == VG_TTE_EMPTY) {
sewardjde4a1d02002-03-22 01:27:54 +0000377 /* Put it here, and set the back pointer. */
378 vg_tt[i] = *tte;
379 VG_WRITE_MISALIGNED_WORD(tte->trans_addr-4, i);
380 vg_tt_used++;
381 return;
382 }
383 i++;
384 if (i == VG_TT_SIZE) i = 0;
385 }
386}
387
388
389/* Copy a new translation's code into TC, leaving a 4-byte hole for
390 the back pointer, and returning a pointer to the code proper (not
391 the hole) in TC.
392*/
393Addr VG_(copy_to_transcache) ( Addr trans_addr, Int trans_size )
394{
395 Int i;
396 Addr ret_addr;
397 if (4+trans_size > VG_TC_SIZE-vg_tc_used)
398 VG_(panic)("copy_to_transcache: not enough free space?!");
399 /* Leave a hole for the back pointer to the TT entry. */
400 vg_tc_used += 4;
401 ret_addr = (Addr)&vg_tc[vg_tc_used];
402 for (i = 0; i < trans_size; i++)
403 vg_tc[vg_tc_used+i] = ((UChar*)trans_addr)[i];
404 vg_tc_used += trans_size;
405 return ret_addr;
406}
407
408
409/* Invalidate the tt_fast cache, for whatever reason. Tricky. We
410 have to find a TTE_EMPTY slot to point all entries at. */
411void VG_(invalidate_tt_fast)( void )
412{
413 Int i, j;
414 for (i = 0; i < VG_TT_SIZE && vg_tt[i].orig_addr != VG_TTE_EMPTY; i++)
415 ;
416 vg_assert(i < VG_TT_SIZE
417 && vg_tt[i].orig_addr == VG_TTE_EMPTY);
418 for (j = 0; j < VG_TT_FAST_SIZE; j++)
419 VG_(tt_fast)[j] = (Addr)&vg_tt[i];
420}
421
422
423/* Search TT to find the translated address of the supplied original,
424 or NULL if not found. This routine is used when we miss in
425 VG_(tt_fast).
426*/
427static __inline__ TTEntry* search_trans_table ( Addr orig_addr )
428{
sewardj18d75132002-05-16 11:06:21 +0000429 //static Int queries = 0;
430 //static Int probes = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000431 Int i;
432 /* Hash to get initial probe point. */
433 // if (queries == 10000) {
434 // VG_(printf)("%d queries, %d probes\n", queries, probes);
435 // queries = probes = 0;
436 //}
437 //queries++;
438 i = ((UInt)orig_addr) % VG_TT_SIZE;
439 while (True) {
sewardj18d75132002-05-16 11:06:21 +0000440 //probes++;
sewardjde4a1d02002-03-22 01:27:54 +0000441 if (vg_tt[i].orig_addr == orig_addr)
442 return &vg_tt[i];
443 if (vg_tt[i].orig_addr == VG_TTE_EMPTY)
444 return NULL;
445 i++;
446 if (i == VG_TT_SIZE) i = 0;
447 }
448}
449
450
451/* Find the translation address for a given (original) code address.
452 If found, update VG_(tt_fast) so subsequent lookups are fast. If
453 no translation can be found, return zero. This routine is (the
454 only one) called from vg_run_innerloop. */
455Addr VG_(search_transtab) ( Addr original_addr )
456{
457 TTEntry* tte;
458 VGP_PUSHCC(VgpSlowFindT);
459 tte = search_trans_table ( original_addr );
460 if (tte == NULL) {
461 /* We didn't find it. vg_run_innerloop will have to request a
462 translation. */
463 VGP_POPCC;
464 return (Addr)0;
465 } else {
466 /* Found it. Put the search result into the fast cache now.
467 Also set the mru_epoch to mark this translation as used. */
468 UInt cno = (UInt)original_addr & VG_TT_FAST_MASK;
469 VG_(tt_fast)[cno] = (Addr)tte;
470 VG_(tt_fast_misses)++;
471 tte->mru_epoch = VG_(current_epoch);
472 VGP_POPCC;
473 return tte->trans_addr;
474 }
475}
476
477
sewardj18d75132002-05-16 11:06:21 +0000478/* Invalidate translations of original code [start .. start + range - 1].
479 This is slow, so you *really* don't want to call it very often.
sewardjde4a1d02002-03-22 01:27:54 +0000480*/
sewardj18d75132002-05-16 11:06:21 +0000481void VG_(invalidate_translations) ( Addr start, UInt range )
sewardjde4a1d02002-03-22 01:27:54 +0000482{
sewardj18d75132002-05-16 11:06:21 +0000483 Addr i_start, i_end, o_start, o_end;
484 UInt out_count, out_osize, out_tsize;
485 Int i;
sewardjde4a1d02002-03-22 01:27:54 +0000486
sewardj18d75132002-05-16 11:06:21 +0000487# ifdef DEBUG_TRANSTAB
488 VG_(sanity_check_tc_tt)();
sewardjde4a1d02002-03-22 01:27:54 +0000489# endif
sewardj18d75132002-05-16 11:06:21 +0000490 i_start = start;
491 i_end = start + range - 1;
492 out_count = out_osize = out_tsize = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000493
sewardj18d75132002-05-16 11:06:21 +0000494 for (i = 0; i < VG_TT_SIZE; i++) {
495 if (vg_tt[i].orig_addr == VG_TTE_EMPTY
496 || vg_tt[i].orig_addr == VG_TTE_DELETED) continue;
497 o_start = vg_tt[i].orig_addr;
498 o_end = o_start + vg_tt[i].orig_size - 1;
499 if (o_end < i_start || o_start > i_end)
500 continue;
501 if (VG_(clo_cachesim))
502 VG_(cachesim_notify_discard)( & vg_tt[i] );
503 vg_tt[i].orig_addr = VG_TTE_DELETED;
504 VG_(this_epoch_out_count) ++;
505 VG_(this_epoch_out_osize) += vg_tt[i].orig_size;
506 VG_(this_epoch_out_tsize) += vg_tt[i].trans_size;
507 VG_(overall_out_count) ++;
508 VG_(overall_out_osize) += vg_tt[i].orig_size;
509 VG_(overall_out_tsize) += vg_tt[i].trans_size;
510 out_count ++;
511 out_osize += vg_tt[i].orig_size;
512 out_tsize += vg_tt[i].trans_size;
sewardjde4a1d02002-03-22 01:27:54 +0000513 }
sewardjde4a1d02002-03-22 01:27:54 +0000514
sewardj18d75132002-05-16 11:06:21 +0000515 if (out_count > 0) {
516 VG_(invalidate_tt_fast)();
517 VG_(sanity_check_tc_tt)();
518# ifdef DEBUG_TRANSTAB
519 { Addr aa;
520 for (aa = i_start; aa <= i_end; aa++)
521 vg_assert(search_trans_table ( aa ) == NULL);
sewardjde4a1d02002-03-22 01:27:54 +0000522 }
sewardj18d75132002-05-16 11:06:21 +0000523# endif
sewardjde4a1d02002-03-22 01:27:54 +0000524 }
525
sewardj18d75132002-05-16 11:06:21 +0000526 if (1|| VG_(clo_verbosity) > 1)
527 VG_(message)(Vg_UserMsg,
528 "discard %d (%d -> %d) translations in range %p .. %p",
529 out_count, out_osize, out_tsize, i_start, i_end );
sewardjde4a1d02002-03-22 01:27:54 +0000530}
531
532
533/*------------------------------------------------------------*/
534/*--- Initialisation. ---*/
535/*------------------------------------------------------------*/
536
sewardj18d75132002-05-16 11:06:21 +0000537void VG_(init_tt_tc) ( void )
sewardjde4a1d02002-03-22 01:27:54 +0000538{
539 Int i;
540
541 /* Allocate the translation table and translation cache. */
542 vg_assert(vg_tc == NULL);
sewardje9047952002-06-05 20:28:33 +0000543 vg_tc = VG_(get_memory_from_mmap) ( VG_TC_SIZE * sizeof(UChar),
544 "trans-cache" );
sewardjde4a1d02002-03-22 01:27:54 +0000545 vg_assert(vg_tc != NULL);
546
547 vg_assert(vg_tt == NULL);
sewardje9047952002-06-05 20:28:33 +0000548 vg_tt = VG_(get_memory_from_mmap) ( VG_TT_SIZE * sizeof(TTEntry),
549 "trans-table" );
sewardjde4a1d02002-03-22 01:27:54 +0000550 vg_assert(vg_tt != NULL);
551
552 /* The main translation table is empty. */
553 vg_tt_used = 0;
554 for (i = 0; i < VG_TT_SIZE; i++) {
555 vg_tt[i].orig_addr = VG_TTE_EMPTY;
556 }
557
558 /* The translation table's fast cache is empty. Point all entries
559 at the first TT entry, which is, of course, empty. */
560 for (i = 0; i < VG_TT_FAST_SIZE; i++)
561 VG_(tt_fast)[i] = (Addr)(&vg_tt[0]);
sewardjde4a1d02002-03-22 01:27:54 +0000562}
563
564/*--------------------------------------------------------------------*/
565/*--- end vg_transtab.c ---*/
566/*--------------------------------------------------------------------*/