aboutsummaryrefslogtreecommitdiffstats
path: root/mps/code/mpm.c
diff options
context:
space:
mode:
authorNick Barnes2001-10-31 14:40:56 +0000
committerNick Barnes2001-10-31 14:40:56 +0000
commit7acfca905d76140f4cc0b09c9a12de237de364cd (patch)
tree3ed8babfa3a73d30f29e08ca5d5adcda4ca4e826 /mps/code/mpm.c
parentb7ce4893f9902d57cd67ac9a92fa6c3d5a8fc833 (diff)
downloademacs-7acfca905d76140f4cc0b09c9a12de237de364cd.tar.gz
emacs-7acfca905d76140f4cc0b09c9a12de237de364cd.zip
Branch imports for masters.
Copied from Perforce Change: 23678 ServerID: perforce.ravenbrook.com
Diffstat (limited to 'mps/code/mpm.c')
-rw-r--r--mps/code/mpm.c525
1 files changed, 525 insertions, 0 deletions
diff --git a/mps/code/mpm.c b/mps/code/mpm.c
new file mode 100644
index 00000000000..8f60f074882
--- /dev/null
+++ b/mps/code/mpm.c
@@ -0,0 +1,525 @@
1/* impl.c.mpm: GENERAL MPM SUPPORT
2 *
3 * $HopeName: MMsrc!mpm.c(trunk.34) $
4 * Copyright (C) 1996 Harlequin Limited. All rights reserved.
5 *
6 * .purpose: Miscellaneous support for the implementation of the MPM
7 * and pool classes.
8 *
9 * .sources: design.mps.writef */
10
11#include "mpm.h"
12#include <stdarg.h>
13/* Get some floating constants for WriteDouble */
14#include <float.h>
15#include <limits.h>
16
17
18SRCID(mpm, "$HopeName: MMsrc!mpm.c(trunk.34) $");
19
20
21/* MPMCheck -- test MPM assumptions */
22
23Bool MPMCheck(void)
24{
25 CHECKL(sizeof(Word) * CHAR_BIT == MPS_WORD_WIDTH);
26 CHECKL(1uL << MPS_WORD_SHIFT == MPS_WORD_WIDTH);
27 CHECKL(AlignCheck(MPS_PF_ALIGN));
28 /* Check that trace ids will fit in the TraceId type. */
29 CHECKL(TraceLIMIT <= UINT_MAX);
30 /* Check that there are enough bits in */
31 /* a TraceSet to store all possible trace ids. */
32 CHECKL(sizeof(TraceSet) * CHAR_BIT >= TraceLIMIT);
33
34 CHECKL((SizeAlignUp(0, 2048) == 0));
35 CHECKL(!SizeIsAligned(64, (unsigned) -1));
36 CHECKL(SizeIsAligned(0, 32));
37 CHECKL((SizeAlignUp(1024, 16) == 1024));
38 /* .prime: 31051 is prime */
39 CHECKL(SizeIsAligned(SizeAlignUp(31051, 256), 256));
40 CHECKL(SizeIsAligned(SizeAlignUp(31051, 512), 512));
41 CHECKL(!SizeIsAligned(31051, 1024));
42 CHECKL(!SizeIsP2(0));
43 CHECKL(SizeIsP2(128));
44 CHECKL(SizeLog2(1L) == 0);
45 CHECKL(SizeLog2(256L) == 8);
46 CHECKL(SizeLog2(65536L) == 16);
47 CHECKL(SizeLog2(131072L) == 17);
48
49 /* .check.writef: We check that various types will fit in a Word; */
50 /* See .writef.check. Don't need to check WriteFS or WriteFF as they */
51 /* should not be cast to Word. */
52 CHECKL(sizeof(WriteFA) <= sizeof(Word));
53 CHECKL(sizeof(WriteFP) <= sizeof(Word));
54 CHECKL(sizeof(WriteFW) <= sizeof(Word)); /* Should be trivial*/
55 CHECKL(sizeof(WriteFU) <= sizeof(Word));
56 CHECKL(sizeof(WriteFB) <= sizeof(Word));
57 CHECKL(sizeof(WriteFC) <= sizeof(Word));
58 /* .check.write.double: See .write.double.check */
59 {
60 int e, DBL_EXP_DIG = 1;
61 for (e = DBL_MAX_10_EXP; e > 0; e /= 10)
62 DBL_EXP_DIG++;
63 CHECKL(DBL_EXP_DIG < DBL_DIG);
64 CHECKL(-(DBL_MIN_10_EXP) <= DBL_MAX_10_EXP);
65 }
66
67 return TRUE;
68}
69
70
71/* FunCheck -- check that a function pointer is valid */
72
73Bool FunCheck(Fun f)
74{
75 CHECKL(f != NULL);
76 /* Could assert various platform-specific things here. */
77 UNUSED(f); /* see .check.unused */
78 return TRUE;
79}
80
81
82/* ShiftCheck -- check that a shift is valid */
83
84Bool ShiftCheck(Shift shift)
85{
86 CHECKL(shift < MPS_WORD_WIDTH); /* standard.ansic 6.3.7 */
87 UNUSED(shift); /* see .check.unused */
88 return TRUE;
89}
90
91
92/* AttrCheck -- check that a set of pool attributes are valid */
93
94Bool AttrCheck(Attr attr)
95{
96 CHECKL((attr & ~AttrMASK) == 0);
97 /* Could check for legal combinations of attributes. */
98 UNUSED(attr); /* see .check.unused */
99 return TRUE;
100}
101
102
103/* AlignCheck -- check that an alignment is valid */
104
105Bool AlignCheck(Align align)
106{
107 CHECKL(align > 0 && (align & (align - 1)) == 0);
108 /* .check.unused: Check methods for signatureless types don't use */
109 /* their argument in hot varieties, so UNUSED is needed. */
110 UNUSED(align);
111 return TRUE;
112}
113
114
115/* WordIsAligned -- test whether a word is aligned */
116
117Bool (WordIsAligned)(Word word, Align align)
118{
119 AVER(AlignCheck(align));
120 return WordIsAligned(word, align);
121}
122
123
124/* WordAlignUp -- round a word up to the nearest aligned value */
125
126Word (WordAlignUp)(Word word, Align align)
127{
128 AVER(AlignCheck(align));
129 return WordAlignUp(word, align);
130}
131
132/* WordRoundUp -- round word up to round.
133 *
134 * .wordroundup.arg.word: The word arg is quantity to be rounded.
135 * .wordroundup.arg.round: The modulus argument is not necessarily an
136 * alignment (i.e., not a power of two).
137 *
138 * .wordroundup.result: Let m be congruent to 0 mod r (m == 0(r)), and
139 * let m be the least m >= w. If w+r-1 (!) is representable in Word
140 * then result is m. Otherwise result is 0. Wittily. (NB. Result may
141 * be 0 even if m is representable.) */
142
143Word (WordRoundUp)(Word word, Size modulus)
144{
145 AVER(modulus > 0);
146 return WordRoundUp(word, modulus);
147}
148
149
150/* WordAlignUp -- round a word down to the nearest aligned value */
151
152Word (WordAlignDown)(Word word, Align alignment)
153{
154 AVER(AlignCheck(alignment));
155 return WordAlignDown(word, alignment);
156}
157
158
159/* SizeIsP2 -- test whether a size is a power of two */
160
161Bool SizeIsP2(Size size)
162{
163 return size > 0 && (size & (size - 1)) == 0;
164}
165
166
167/* Logarithms */
168
169Shift SizeFloorLog2(Size size)
170{
171 Shift l = 0;
172
173 AVER(size != 0);
174 while(size > 1) {
175 ++l;
176 size >>= 1;
177 }
178 return l;
179}
180
181Shift SizeLog2(Size size)
182{
183 AVER(SizeIsP2(size));
184 return SizeFloorLog2(size);
185}
186
187
188/* AddrAlignDown -- round a word down to the nearest aligned value */
189
190Addr (AddrAlignDown)(Addr addr, Align alignment)
191{
192 AVER(AlignCheck(alignment));
193 return AddrAlignDown(addr, alignment);
194}
195
196
197/* ResIsAllocFailure
198 *
199 * Test whether a result code is in the set of allocation failure codes. */
200
201Bool ResIsAllocFailure(Res res)
202{
203 return (res == ResMEMORY || res == ResRESOURCE || res == ResCOMMIT_LIMIT);
204}
205
206
207/* WriteWord -- output a textual representation of a word to a stream
208 *
209 * Output as an unsigned value in the given base (2-16), padded to the
210 * given width. */
211
212static Res WriteWord(mps_lib_FILE *stream, Word w, unsigned base,
213 unsigned width)
214{
215 static const char digit[16] = "0123456789ABCDEF";
216 static const char pad = '0'; /* padding character */
217 char buf[MPS_WORD_WIDTH + 1]; /* enough for binary, */
218 /* plus one for terminator */
219 unsigned i;
220 int r;
221
222 AVER(stream != NULL);
223 AVER(2 <= base && base <= 16);
224 AVER(width <= MPS_WORD_WIDTH);
225
226 /* Add digits to the buffer starting at the right-hand end, so that */
227 /* the buffer forms a string representing the number. A do...while */
228 /* loop is used to ensure that at least one digit (zero) is written */
229 /* when the number is zero. */
230 i = MPS_WORD_WIDTH;
231 buf[i] = '\0';
232 do {
233 --i;
234 buf[i] = digit[w % base];
235 w /= base;
236 } while(w > 0);
237
238 /* If the number is not as wide as the requested field, pad out the */
239 /* buffer with zeros. */
240 while(i > MPS_WORD_WIDTH - width) {
241 --i;
242 buf[i] = pad;
243 }
244
245 r = mps_lib_fputs(&buf[i], stream);
246 if (r == mps_lib_EOF)
247 return ResIO;
248
249 return ResOK;
250}
251
252
253/* WriteDouble -- write a double float to a stream
254 *
255 * Cf.: Guy L. Steele, Jr. and Jon L. White, "How to print
256 * floating-point numbers accurately", ACM SIGPLAN Notices, Vol. 25,
257 * No. 6 (Jun. 1990), Pages 112-126
258 *
259 * .write.double.limitation: Only the "simple" printer is implemented
260 * here.
261 *
262 * .write.double.check: There being no DBL_EXP_DIG, we assume that it is
263 * less than DBL_DIG. */
264
265static Res WriteDouble(mps_lib_FILE *stream, double d)
266{
267 double F = d;
268 int E = 0, i, x = 0;
269 /* Largest exponent that will print in %f style. Larger will use %e */
270 /* style. DBL_DIG is chosen for use of doubles as extra-large integers. */
271 int expmax = DBL_DIG;
272 /* Smallest exponent that will print in %f style. Smaller will use */
273 /* %e style. -4 is chosen because it is the %g default. */
274 int expmin = -4;
275 /* Epsilon defines how many digits will be printed. Using DBL_EPSILON */
276 /* prints all the significant digits. To print fewer digits, set */
277 /* epsilon to 10 ^ - N, where N is the desired number of digits. */
278 double epsilon = DBL_EPSILON / 2;
279 char digits[] = "0123456789";
280 /* sign, DBL_DIG, '0.', 'e', '+/-', log10(DBL_MAX_10_EXP), */
281 /* terminator. See .write.double.check. */
282 char buf[1+DBL_DIG+2+1+1+DBL_DIG+1];
283 int j = 0;
284
285 if (F == 0.0) {
286 if (mps_lib_fputs("0", stream) == mps_lib_EOF)
287 return ResIO;
288 return ResOK;
289 }
290
291 if (F < 0) {
292 buf[j] = '-';
293 j++;
294 F = - F;
295 }
296
297 /* This scaling operation could introduce rounding errors. */
298 for ( ; F >= 1.0 ; F /= 10.0) {
299 E++;
300 if (E > DBL_MAX_10_EXP) {
301 if (mps_lib_fputs("Infinity", stream) == mps_lib_EOF)
302 return ResIO;
303 return ResOK;
304 }
305 }
306 for ( ; F < 0.1; F *= 10)
307 E--;
308
309 /* See if %e notation is required */
310 if (E > expmax || E <= expmin) {
311 x = E - 1;
312 E = 1;
313 }
314
315 /* Insert leading 0's */
316 if (E <= 0) {
317 buf[j] = '0';
318 j++;
319 }
320 if (E < 0) {
321 buf[j] = '.';
322 j++;
323 }
324 for (i = -E; i > 0; i--) {
325 buf[j] = '0';
326 j++;
327 }
328
329 /* Convert the fraction to base 10, inserting a decimal according to */
330 /* the exponent. This is Steele and White's FP3 algorithm. */
331 do {
332 int U;
333
334 if (E == 0) {
335 buf[j] = '.';
336 j++;
337 }
338 F *= 10.0;
339 U = (int)F;
340 F = F - U;
341 epsilon *= 10.0;
342 E--;
343 if (F < epsilon || F > 1.0 - epsilon) {
344 if (F < 0.5)
345 buf[j] = digits[U];
346 else
347 buf[j] = digits[U + 1];
348 j++;
349 break;
350 }
351 buf[j] = digits[U];
352 j++;
353 } while (1);
354
355 /* Insert trailing 0's */
356 for (i = E; i > 0; i--) {
357 buf[j] = '0';
358 j++;
359 }
360
361 /* If %e notation is selected, append the exponent indicator and sign. */
362 if (x != 0) {
363 buf[j] = 'e';
364 j++;
365 if (x < 0) {
366 buf[j] = '-';
367 j++;
368 x = - x;
369 }
370 else {
371 buf[j] = '+';
372 j++;
373 }
374
375 /* Format the exponent to at least two digits. */
376 for (i = 100; i <= x; )
377 i *= 10;
378 i /= 10;
379 do {
380 buf[j] = digits[x / i];
381 j++;
382 x %= i;
383 i /= 10;
384 } while (i > 0);
385 }
386 buf[j] = '\0'; /* arnold */
387
388 if (mps_lib_fputs(buf, stream) == mps_lib_EOF)
389 return ResIO;
390 return ResOK;
391}
392
393
394/* WriteF -- write formatted output
395 *
396 * .writef.des: See design.mps.writef, also design.mps.lib
397 *
398 * .writef.p: There is an assumption that void * fits in Word in
399 * the case of $P, and unsigned long for $U and $B. This is checked in
400 * MPMCheck.
401 *
402 * .writef.div: Although MPS_WORD_WIDTH/4 appears three times, there
403 * are effectively three separate decisions to format at this width.
404 *
405 * .writef.check: See .check.writef. */
406
407Res WriteF(mps_lib_FILE *stream, ...)
408{
409 const char *format;
410 int r;
411 size_t i;
412 Res res;
413 va_list args;
414
415 AVER(stream != NULL);
416
417 va_start(args, stream);
418
419 for(;;) {
420 format = va_arg(args, const char *);
421 if (format == NULL)
422 break;
423
424 while(*format != '\0') {
425 if (*format != '$') {
426 r = mps_lib_fputc(*format, stream); /* Could be more efficient */
427 if (r == mps_lib_EOF) return ResIO;
428 } else {
429 ++format;
430 AVER(*format != '\0');
431
432 switch(*format) {
433 case 'A': { /* address */
434 WriteFA addr = va_arg(args, WriteFA);
435 res = WriteWord(stream, (Word)addr, 16,
436 (sizeof(WriteFA) * CHAR_BIT + 3) / 4);
437 if (res != ResOK) return res;
438 } break;
439
440 case 'P': { /* pointer, see .writef.p */
441 WriteFP p = va_arg(args, WriteFP);
442 res = WriteWord(stream, (Word)p, 16,
443 (sizeof(WriteFP) * CHAR_BIT + 3)/ 4);
444 if (res != ResOK) return res;
445 } break;
446
447 case 'F': { /* function */
448 WriteFF f = va_arg(args, WriteFF);
449 Byte *b = (Byte *)&f;
450 for(i=0; i < sizeof(WriteFF); i++) {
451 res = WriteWord(stream, (Word)(b[i]), 16,
452 (CHAR_BIT + 3) / 4);
453 if (res != ResOK) return res;
454 }
455 } break;
456
457 case 'S': { /* string */
458 WriteFS s = va_arg(args, WriteFS);
459 r = mps_lib_fputs((const char *)s, stream);
460 if (r == mps_lib_EOF) return ResIO;
461 } break;
462
463 case 'C': { /* character */
464 WriteFC c = va_arg(args, WriteFC); /* promoted */
465 r = mps_lib_fputc((int)c, stream);
466 if (r == mps_lib_EOF) return ResIO;
467 } break;
468
469 case 'W': { /* word */
470 WriteFW w = va_arg(args, WriteFW);
471 res = WriteWord(stream, (Word)w, 16,
472 (sizeof(WriteFW) * CHAR_BIT + 3) / 4);
473 if (res != ResOK) return res;
474 } break;
475
476 case 'U': { /* decimal, see .writef.p */
477 WriteFU u = va_arg(args, WriteFU);
478 res = WriteWord(stream, (Word)u, 10, 0);
479 if (res != ResOK) return res;
480 } break;
481
482 case 'B': { /* binary, see .writef.p */
483 WriteFB b = va_arg(args, WriteFB);
484 res = WriteWord(stream, (Word)b, 2, sizeof(WriteFB) * CHAR_BIT);
485 if (res != ResOK) return res;
486 } break;
487
488 case '$': { /* dollar char */
489 r = mps_lib_fputc('$', stream);
490 if (r == mps_lib_EOF) return ResIO;
491 } break;
492
493 case 'D': { /* double */
494 WriteFD d = va_arg(args, WriteFD);
495 res = WriteDouble(stream, d);
496 if (res != ResOK) return res;
497 } break;
498
499 default:
500 NOTREACHED;
501 }
502 }
503
504 ++format;
505 }
506 }
507
508 va_end(args);
509
510 return ResOK;
511}
512
513
514/* StringLength -- Slow substitute for strlen */
515
516size_t StringLength(const char *s)
517{
518 size_t i;
519
520 AVER(s != NULL);
521
522 for(i = 0; s[i] != '\0'; i++)
523 NOOP;
524 return(i);
525}