blob: a364df0b865fa4baa75fd6114a5c13fc53fb9851 [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. */
106#define VG_READ_MISALIGNED_WORD(aaa) (*((UInt*)(aaa)))
107#define VG_WRITE_MISALIGNED_WORD(aaa,vvv) *((UInt*)(aaa)) = ((UInt)(vvv))
108
109/* Used for figuring out an age threshold for translations. */
110static Int vg_bytes_in_epoch[VG_N_EPOCHS];
111static Int vg_entries_in_epoch[VG_N_EPOCHS];
112
113
114/* Just so these counts can be queried without making them globally
115 visible. */
116void VG_(get_tt_tc_used) ( UInt* tt_used, UInt* tc_used )
117{
118 *tt_used = vg_tt_used;
119 *tc_used = vg_tc_used;
120}
121
122
123/* Do the LRU thing on TT/TC, clearing them back to the target limits
124 if they are over the threshold limits.
125*/
126void VG_(maybe_do_lru_pass) ( void )
127{
128 Int i, j, r, w, thresh, ttno;
129 TTEntry* tte;
130
sewardj215e7f02002-05-02 03:47:01 +0000131 const Int tc_limit = (Int)(((double)VG_TC_SIZE * (double)VG_TC_LIMIT_PERCENT)
132 / (double)100.0);
133 const Int tt_limit = (Int)(((double)VG_TT_SIZE * (double)VG_TT_LIMIT_PERCENT)
134 / (double)100.0);
135 const Int tc_target = (Int)(((double)VG_TC_SIZE * (double)VG_TC_TARGET_PERCENT)
136 / (double)100.0);
137 const Int tt_target = (Int)(((double)VG_TT_SIZE * (double)VG_TT_TARGET_PERCENT)
138 / (double)100.0);
sewardjde4a1d02002-03-22 01:27:54 +0000139
140 /* Decide quickly if we need to do an LRU pass ? */
141 if (vg_tc_used <= tc_limit && vg_tt_used <= tt_limit)
142 return;
143
sewardj18d75132002-05-16 11:06:21 +0000144# ifdef DEBUG_TRANSTAB
145 VG_(sanity_check_tc_tt)();
146# endif
147
sewardjde4a1d02002-03-22 01:27:54 +0000148 VGP_PUSHCC(VgpDoLRU);
149 /*
150 VG_(printf)(
151 "limits: tc_limit %d, tt_limit %d, tc_target %d, tt_target %d\n",
152 tc_limit, tt_limit, tc_target, tt_target);
153 */
154
155 if (VG_(clo_verbosity) > 2)
156 VG_(printf)(" pre-LRU: tc %d (target %d), tt %d (target %d)\n",
157 vg_tc_used, tc_target, vg_tt_used, tt_target);
158
159 /* Yes we do. Figure out what threshold age is required in order to
160 shrink both the TC and TT occupancy below TC_TARGET_PERCENT and
161 TT_TARGET_PERCENT respectively. */
162
163 VG_(number_of_lrus)++;
164
165 /* Count the number of TC bytes and TT entries in each epoch. */
166 for (i = 0; i < VG_N_EPOCHS; i++)
167 vg_bytes_in_epoch[i] = vg_entries_in_epoch[i] = 0;
168
169 for (i = 0; i < VG_TT_SIZE; i++) {
sewardj18d75132002-05-16 11:06:21 +0000170 if (vg_tt[i].orig_addr == VG_TTE_EMPTY
171 || vg_tt[i].orig_addr == VG_TTE_DELETED)
172 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000173 j = vg_tt[i].mru_epoch;
174 vg_assert(j <= VG_(current_epoch));
175 j = VG_(current_epoch) - j;
176 if (j >= VG_N_EPOCHS) j = VG_N_EPOCHS-1;
177 vg_assert(0 <= j && j < VG_N_EPOCHS);
178 /* Greater j now means older. */
179 vg_entries_in_epoch[j]++;
180 vg_bytes_in_epoch[j] += 4+vg_tt[i].trans_size;
181 }
182
183 /*
184 for (i = 0; i < VG_N_EPOCHS; i++)
185 VG_(printf)("epoch %d: ents %d, bytes %d\n",
186 i, vg_entries_in_epoch[i], vg_bytes_in_epoch[i]);
187 */
188
189 /* Cumulatise. Make vg_{bytes,entries}_in_epoch[n] contain the
190 counts for itself and all younger epochs. */
191 for (i = 1; i < VG_N_EPOCHS; i++) {
192 vg_entries_in_epoch[i] += vg_entries_in_epoch[i-1];
193 vg_bytes_in_epoch[i] += vg_bytes_in_epoch[i-1];
194 }
195
196 for (thresh = 0; thresh < VG_N_EPOCHS; thresh++) {
197 if (vg_entries_in_epoch[thresh] > tt_target
198 || vg_bytes_in_epoch[thresh] >= tc_target)
199 break;
200 }
201
202 if (VG_(clo_verbosity) > 2)
203 VG_(printf)(
204 " LRU: discard translations %d or more epochs since last use\n",
205 thresh
206 );
207
208 thresh = VG_(current_epoch) - thresh;
209
210 /* Ok, so we will hit our targets if we retain all entries most
211 recently used at most thresh epochs ago. Traverse the TT and
212 mark such entries as deleted. */
213 for (i = 0; i < VG_TT_SIZE; i++) {
sewardj18d75132002-05-16 11:06:21 +0000214 if (vg_tt[i].orig_addr == VG_TTE_EMPTY
215 || vg_tt[i].orig_addr == VG_TTE_DELETED)
216 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000217 if (vg_tt[i].mru_epoch <= thresh) {
218 vg_tt[i].orig_addr = VG_TTE_DELETED;
sewardjde4a1d02002-03-22 01:27:54 +0000219 VG_(this_epoch_out_count) ++;
220 VG_(this_epoch_out_osize) += vg_tt[i].orig_size;
221 VG_(this_epoch_out_tsize) += vg_tt[i].trans_size;
222 VG_(overall_out_count) ++;
223 VG_(overall_out_osize) += vg_tt[i].orig_size;
224 VG_(overall_out_tsize) += vg_tt[i].trans_size;
225 }
226 }
227
sewardjde4a1d02002-03-22 01:27:54 +0000228 /* Now compact the TC, sliding live entries downwards to fill spaces
229 left by deleted entries. In this loop, r is the offset in TC of
230 the current translation under consideration, and w is the next
231 allocation point. */
232 r = w = 0;
233 while (True) {
234 if (r >= vg_tc_used) break;
235 /* The first four bytes of every translation contain the index
236 of its TT entry. The TT entry's .trans_addr field points at
237 the start of the code proper, not at this 4-byte index, so
238 that we don't constantly have to keep adding 4 in the main
239 lookup/dispatch loop. */
240 ttno = VG_READ_MISALIGNED_WORD(&vg_tc[r]);
241 vg_assert(ttno >= 0 && ttno < VG_TT_SIZE);
242 tte = & vg_tt[ ttno ];
243 vg_assert(tte->orig_addr != VG_TTE_EMPTY);
244 if (tte->orig_addr != VG_TTE_DELETED) {
245 /* We want to keep this one alive. */
246 /* Sanity check the pointer back to TC. */
247 vg_assert(tte->trans_addr == (Addr)&vg_tc[r+4]);
248 for (i = 0; i < 4+tte->trans_size; i++)
249 vg_tc[w+i] = vg_tc[r+i];
250 tte->trans_addr = (Addr)&vg_tc[w+4];
251 w += 4+tte->trans_size;
sewardj18d75132002-05-16 11:06:21 +0000252 } else {
253 tte->orig_addr = VG_TTE_EMPTY;
254 vg_tt_used--;
sewardjde4a1d02002-03-22 01:27:54 +0000255 }
256 r += 4+tte->trans_size;
257 }
258 /* should have traversed an exact number of translations, with no
259 slop at the end. */
260 vg_assert(w <= r);
261 vg_assert(r == vg_tc_used);
262 vg_assert(w <= r);
263 vg_assert(w <= tc_target);
264 vg_tc_used = w;
265
sewardj18d75132002-05-16 11:06:21 +0000266 vg_assert(vg_tt_used >= 0);
267 vg_assert(vg_tt_used <= tt_target);
268
sewardjde4a1d02002-03-22 01:27:54 +0000269 /* Invalidate the fast cache, since it is now out of date. It will get
270 reconstructed incrementally when the client resumes. */
271 VG_(invalidate_tt_fast)();
272
273 if (VG_(clo_verbosity) > 2)
274 VG_(printf)("post-LRU: tc %d (target %d), tt %d (target %d)\n",
275 vg_tc_used, tc_target, vg_tt_used, tt_target);
276
277 if (VG_(clo_verbosity) > 1)
278 VG_(message)(Vg_UserMsg,
279 "epoch %d (bb %luk): thresh %d, "
280 "out %d (%dk -> %dk), new TT %d, TC %dk",
281 VG_(current_epoch),
282 VG_(bbs_done) / 1000,
283 VG_(current_epoch) - thresh,
284 VG_(this_epoch_out_count),
285 VG_(this_epoch_out_osize) / 1000,
286 VG_(this_epoch_out_tsize) / 1000,
287 vg_tt_used, vg_tc_used / 1000
288 );
289
290 /* Reconstruct the SMC detection structures. */
sewardj18d75132002-05-16 11:06:21 +0000291# ifdef DEBUG_TRANSTAB
292 for (i = 0; i < VG_TT_SIZE; i++)
293 vg_assert(vg_tt[i].orig_addr != VG_TTE_DELETED);
294# endif
295 VG_(sanity_check_tc_tt)();
sewardjde4a1d02002-03-22 01:27:54 +0000296
297 VGP_POPCC;
298}
299
300
301/* Do a sanity check on TT/TC.
302*/
303void VG_(sanity_check_tc_tt) ( void )
304{
305 Int i, counted_entries, counted_bytes;
306 TTEntry* tte;
307 counted_entries = 0;
308 counted_bytes = 0;
309 for (i = 0; i < VG_TT_SIZE; i++) {
310 tte = &vg_tt[i];
311 if (tte->orig_addr == VG_TTE_EMPTY) continue;
sewardjde4a1d02002-03-22 01:27:54 +0000312 vg_assert(tte->mru_epoch >= 0);
313 vg_assert(tte->mru_epoch <= VG_(current_epoch));
314 counted_entries++;
315 counted_bytes += 4+tte->trans_size;
316 vg_assert(tte->trans_addr >= (Addr)&vg_tc[4]);
317 vg_assert(tte->trans_addr < (Addr)&vg_tc[vg_tc_used]);
318 vg_assert(VG_READ_MISALIGNED_WORD(tte->trans_addr-4) == i);
319 }
320 vg_assert(counted_entries == vg_tt_used);
321 vg_assert(counted_bytes == vg_tc_used);
322}
323
324
325/* Add this already-filled-in entry to the TT. Assumes that the
326 relevant code chunk has been placed in TC, along with a dummy back
327 pointer, which is inserted here.
328*/
329extern void VG_(add_to_trans_tab) ( TTEntry* tte )
330{
331 Int i;
332 /*
333 VG_(printf)("add_to_trans_tab(%d) %x %d %x %d\n",
334 vg_tt_used, tte->orig_addr, tte->orig_size,
335 tte->trans_addr, tte->trans_size);
336 */
337 vg_assert(tte->orig_addr != VG_TTE_DELETED
338 && tte->orig_addr != VG_TTE_EMPTY);
339 /* Hash to get initial probe point. */
340 i = ((UInt)(tte->orig_addr)) % VG_TT_SIZE;
341 while (True) {
342 if (vg_tt[i].orig_addr == tte->orig_addr)
343 VG_(panic)("add_to_trans_tab: duplicate");
sewardj18d75132002-05-16 11:06:21 +0000344 if (vg_tt[i].orig_addr == VG_TTE_EMPTY) {
sewardjde4a1d02002-03-22 01:27:54 +0000345 /* Put it here, and set the back pointer. */
346 vg_tt[i] = *tte;
347 VG_WRITE_MISALIGNED_WORD(tte->trans_addr-4, i);
348 vg_tt_used++;
349 return;
350 }
351 i++;
352 if (i == VG_TT_SIZE) i = 0;
353 }
354}
355
356
357/* Copy a new translation's code into TC, leaving a 4-byte hole for
358 the back pointer, and returning a pointer to the code proper (not
359 the hole) in TC.
360*/
361Addr VG_(copy_to_transcache) ( Addr trans_addr, Int trans_size )
362{
363 Int i;
364 Addr ret_addr;
365 if (4+trans_size > VG_TC_SIZE-vg_tc_used)
366 VG_(panic)("copy_to_transcache: not enough free space?!");
367 /* Leave a hole for the back pointer to the TT entry. */
368 vg_tc_used += 4;
369 ret_addr = (Addr)&vg_tc[vg_tc_used];
370 for (i = 0; i < trans_size; i++)
371 vg_tc[vg_tc_used+i] = ((UChar*)trans_addr)[i];
372 vg_tc_used += trans_size;
373 return ret_addr;
374}
375
376
377/* Invalidate the tt_fast cache, for whatever reason. Tricky. We
378 have to find a TTE_EMPTY slot to point all entries at. */
379void VG_(invalidate_tt_fast)( void )
380{
381 Int i, j;
382 for (i = 0; i < VG_TT_SIZE && vg_tt[i].orig_addr != VG_TTE_EMPTY; i++)
383 ;
384 vg_assert(i < VG_TT_SIZE
385 && vg_tt[i].orig_addr == VG_TTE_EMPTY);
386 for (j = 0; j < VG_TT_FAST_SIZE; j++)
387 VG_(tt_fast)[j] = (Addr)&vg_tt[i];
388}
389
390
391/* Search TT to find the translated address of the supplied original,
392 or NULL if not found. This routine is used when we miss in
393 VG_(tt_fast).
394*/
395static __inline__ TTEntry* search_trans_table ( Addr orig_addr )
396{
sewardj18d75132002-05-16 11:06:21 +0000397 //static Int queries = 0;
398 //static Int probes = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000399 Int i;
400 /* Hash to get initial probe point. */
401 // if (queries == 10000) {
402 // VG_(printf)("%d queries, %d probes\n", queries, probes);
403 // queries = probes = 0;
404 //}
405 //queries++;
406 i = ((UInt)orig_addr) % VG_TT_SIZE;
407 while (True) {
sewardj18d75132002-05-16 11:06:21 +0000408 //probes++;
sewardjde4a1d02002-03-22 01:27:54 +0000409 if (vg_tt[i].orig_addr == orig_addr)
410 return &vg_tt[i];
411 if (vg_tt[i].orig_addr == VG_TTE_EMPTY)
412 return NULL;
413 i++;
414 if (i == VG_TT_SIZE) i = 0;
415 }
416}
417
418
419/* Find the translation address for a given (original) code address.
420 If found, update VG_(tt_fast) so subsequent lookups are fast. If
421 no translation can be found, return zero. This routine is (the
422 only one) called from vg_run_innerloop. */
423Addr VG_(search_transtab) ( Addr original_addr )
424{
425 TTEntry* tte;
426 VGP_PUSHCC(VgpSlowFindT);
427 tte = search_trans_table ( original_addr );
428 if (tte == NULL) {
429 /* We didn't find it. vg_run_innerloop will have to request a
430 translation. */
431 VGP_POPCC;
432 return (Addr)0;
433 } else {
434 /* Found it. Put the search result into the fast cache now.
435 Also set the mru_epoch to mark this translation as used. */
436 UInt cno = (UInt)original_addr & VG_TT_FAST_MASK;
437 VG_(tt_fast)[cno] = (Addr)tte;
438 VG_(tt_fast_misses)++;
439 tte->mru_epoch = VG_(current_epoch);
440 VGP_POPCC;
441 return tte->trans_addr;
442 }
443}
444
445
sewardj18d75132002-05-16 11:06:21 +0000446/* Invalidate translations of original code [start .. start + range - 1].
447 This is slow, so you *really* don't want to call it very often.
sewardjde4a1d02002-03-22 01:27:54 +0000448*/
sewardj18d75132002-05-16 11:06:21 +0000449void VG_(invalidate_translations) ( Addr start, UInt range )
sewardjde4a1d02002-03-22 01:27:54 +0000450{
sewardj18d75132002-05-16 11:06:21 +0000451 Addr i_start, i_end, o_start, o_end;
452 UInt out_count, out_osize, out_tsize;
453 Int i;
sewardjde4a1d02002-03-22 01:27:54 +0000454
sewardj18d75132002-05-16 11:06:21 +0000455# ifdef DEBUG_TRANSTAB
456 VG_(sanity_check_tc_tt)();
sewardjde4a1d02002-03-22 01:27:54 +0000457# endif
sewardj18d75132002-05-16 11:06:21 +0000458 i_start = start;
459 i_end = start + range - 1;
460 out_count = out_osize = out_tsize = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000461
sewardj18d75132002-05-16 11:06:21 +0000462 for (i = 0; i < VG_TT_SIZE; i++) {
463 if (vg_tt[i].orig_addr == VG_TTE_EMPTY
464 || vg_tt[i].orig_addr == VG_TTE_DELETED) continue;
465 o_start = vg_tt[i].orig_addr;
466 o_end = o_start + vg_tt[i].orig_size - 1;
467 if (o_end < i_start || o_start > i_end)
468 continue;
469 if (VG_(clo_cachesim))
470 VG_(cachesim_notify_discard)( & vg_tt[i] );
471 vg_tt[i].orig_addr = VG_TTE_DELETED;
472 VG_(this_epoch_out_count) ++;
473 VG_(this_epoch_out_osize) += vg_tt[i].orig_size;
474 VG_(this_epoch_out_tsize) += vg_tt[i].trans_size;
475 VG_(overall_out_count) ++;
476 VG_(overall_out_osize) += vg_tt[i].orig_size;
477 VG_(overall_out_tsize) += vg_tt[i].trans_size;
478 out_count ++;
479 out_osize += vg_tt[i].orig_size;
480 out_tsize += vg_tt[i].trans_size;
sewardjde4a1d02002-03-22 01:27:54 +0000481 }
sewardjde4a1d02002-03-22 01:27:54 +0000482
sewardj18d75132002-05-16 11:06:21 +0000483 if (out_count > 0) {
484 VG_(invalidate_tt_fast)();
485 VG_(sanity_check_tc_tt)();
486# ifdef DEBUG_TRANSTAB
487 { Addr aa;
488 for (aa = i_start; aa <= i_end; aa++)
489 vg_assert(search_trans_table ( aa ) == NULL);
sewardjde4a1d02002-03-22 01:27:54 +0000490 }
sewardj18d75132002-05-16 11:06:21 +0000491# endif
sewardjde4a1d02002-03-22 01:27:54 +0000492 }
493
sewardj18d75132002-05-16 11:06:21 +0000494 if (1|| VG_(clo_verbosity) > 1)
495 VG_(message)(Vg_UserMsg,
496 "discard %d (%d -> %d) translations in range %p .. %p",
497 out_count, out_osize, out_tsize, i_start, i_end );
sewardjde4a1d02002-03-22 01:27:54 +0000498}
499
500
501/*------------------------------------------------------------*/
502/*--- Initialisation. ---*/
503/*------------------------------------------------------------*/
504
sewardj18d75132002-05-16 11:06:21 +0000505void VG_(init_tt_tc) ( void )
sewardjde4a1d02002-03-22 01:27:54 +0000506{
507 Int i;
508
509 /* Allocate the translation table and translation cache. */
510 vg_assert(vg_tc == NULL);
511 vg_tc = VG_(get_memory_from_mmap) ( VG_TC_SIZE * sizeof(UChar) );
512 vg_assert(vg_tc != NULL);
513
514 vg_assert(vg_tt == NULL);
515 vg_tt = VG_(get_memory_from_mmap) ( VG_TT_SIZE * sizeof(TTEntry) );
516 vg_assert(vg_tt != NULL);
517
518 /* The main translation table is empty. */
519 vg_tt_used = 0;
520 for (i = 0; i < VG_TT_SIZE; i++) {
521 vg_tt[i].orig_addr = VG_TTE_EMPTY;
522 }
523
524 /* The translation table's fast cache is empty. Point all entries
525 at the first TT entry, which is, of course, empty. */
526 for (i = 0; i < VG_TT_FAST_SIZE; i++)
527 VG_(tt_fast)[i] = (Addr)(&vg_tt[0]);
sewardjde4a1d02002-03-22 01:27:54 +0000528}
529
530/*--------------------------------------------------------------------*/
531/*--- end vg_transtab.c ---*/
532/*--------------------------------------------------------------------*/