void report_break (char* message) { mps_lib_FILE *stream = mps_lib_get_stdout(); mps_lib_fputs("Break to debugger:\n ", stream); mps_lib_fputs(message, stream); mps_lib_fputc('\n', stream); DebugBreak(); }
void report_error (char* message) { mps_lib_FILE *stream = mps_lib_get_stderr(); mps_lib_fputs("\nError:\n", stream); mps_lib_fputs(message, stream); mps_lib_fputc('\n', stream); mps_lib_abort(); }
void display_integer (int integer, mps_lib_FILE *stream) { /* This is naieve. Assume no more than 7 digits */ int remainder = integer; int leading = 1; int power; if (integer == 0) { /* special case needs the leading zero */ mps_lib_fputs(" 0", stream); return; } for (power = 10000000; power > 0; power = power / 10) { int exponent = (int)(log10(power)); int digit = remainder / power; remainder = remainder % power; if (digit == 0) { mps_lib_fputc(leading ? ' ' : '0', stream); } else { leading = 0; mps_lib_fputc('0' + digit, stream); }; if ((exponent == 6) || (exponent == 3)) if (digit == 0) { mps_lib_fputc(leading ? ' ' : ',', stream); } else mps_lib_fputc(',', stream); } }
void display_wrapper_stats () { int largest; mps_lib_FILE *stream = mps_lib_get_stdout(); char *message = "Start of heap statistics"; mps_lib_fputc('\n', stream); mps_lib_fputs(message, stream); display_padding_for_string(message, ' ', class_name_size, stream); mps_lib_fputs(" (count) (size)", stream); mps_lib_fputs("\n\n", stream); display_totals(stream); mps_lib_fputc('\n', stream); for (largest = biggest_below_value(very_big); largest >= 0; largest = biggest_below_value(largest)) { display_wrappers_of_size(largest, stream); } mps_lib_fputs("End of heap statistics\n\n", stream); }
void display_wrapper_breakpoints() { mps_lib_FILE *stream = mps_lib_get_stdout(); if (wrapper_breaks_cursor >= 0) { int i; mps_lib_fputs("Object allocation breakpoints\n\n", stream); mps_lib_fputs(" (class-name) (count)\n\n", stream); for (i = 0; i < wrapper_breaks_cursor + 1; i++) { wrapper_stats_t wrapper_record = wrapper_breaks + i; char *class_name = class_name_from_wrapper(wrapper_record->wrapper_address); mps_lib_fputs_(class_name, class_name_size, stream); display_padding_for_string(class_name, ' ', class_name_size, stream); display_integer(wrapper_record->usage_size, stream); mps_lib_fputc('\n', stream); } } else mps_lib_fputs("No active object allocation breakpoints\n\n", stream); }
static Res WriteULongest(mps_lib_FILE *stream, ULongest w, unsigned base, unsigned width) { static const char digit[16 + 1] = "0123456789ABCDEF"; /* + 1 for terminator: unused, but prevents compiler warning */ static const char pad = '0'; /* padding character */ char buf[MPS_WORD_WIDTH + 1]; /* enough for binary, */ /* plus one for terminator */ unsigned i; int r; AVER(stream != NULL); AVER(2 <= base); AVER(base <= 16); AVER(width <= MPS_WORD_WIDTH); /* Add digits to the buffer starting at the right-hand end, so that */ /* the buffer forms a string representing the number. A do...while */ /* loop is used to ensure that at least one digit (zero) is written */ /* when the number is zero. */ i = MPS_WORD_WIDTH; buf[i] = '\0'; do { --i; buf[i] = digit[w % base]; w /= base; } while(w > 0); /* If the number is not as wide as the requested field, pad out the */ /* buffer with zeros. */ while(i > MPS_WORD_WIDTH - width) { --i; buf[i] = pad; } r = mps_lib_fputs(&buf[i], stream); if (r == mps_lib_EOF) return ResIO; return ResOK; }
void report_message (char* message) { mps_lib_FILE *stream = mps_lib_get_stdout(); mps_lib_fputs(message, stream); }
Res WriteF_firstformat_v(mps_lib_FILE *stream, const char *firstformat, va_list args) { const char *format; int r; size_t i; Res res; AVER(stream != NULL); format = firstformat; for(;;) { if (format == NULL) break; while(*format != '\0') { if (*format != '$') { r = mps_lib_fputc(*format, stream); /* Could be more efficient */ if (r == mps_lib_EOF) return ResIO; } else { ++format; AVER(*format != '\0'); switch(*format) { case 'A': { /* address */ WriteFA addr = va_arg(args, WriteFA); res = WriteULongest(stream, (ULongest)addr, 16, (sizeof(WriteFA) * CHAR_BIT + 3) / 4); if (res != ResOK) return res; } break; case 'P': { /* pointer, see .writef.p */ WriteFP p = va_arg(args, WriteFP); res = WriteULongest(stream, (ULongest)p, 16, (sizeof(WriteFP) * CHAR_BIT + 3)/ 4); if (res != ResOK) return res; } break; case 'F': { /* function */ WriteFF f = va_arg(args, WriteFF); Byte *b = (Byte *)&f; /* ISO C forbits casting function pointers to integer, so decode bytes (see design.writef.f). TODO: Be smarter about endianness. */ for(i=0; i < sizeof(WriteFF); i++) { res = WriteULongest(stream, (ULongest)(b[i]), 16, (CHAR_BIT + 3) / 4); if (res != ResOK) return res; } } break; case 'S': { /* string */ WriteFS s = va_arg(args, WriteFS); r = mps_lib_fputs((const char *)s, stream); if (r == mps_lib_EOF) return ResIO; } break; case 'C': { /* character */ WriteFC c = va_arg(args, WriteFC); /* promoted */ r = mps_lib_fputc((int)c, stream); if (r == mps_lib_EOF) return ResIO; } break; case 'W': { /* word */ WriteFW w = va_arg(args, WriteFW); res = WriteULongest(stream, (ULongest)w, 16, (sizeof(WriteFW) * CHAR_BIT + 3) / 4); if (res != ResOK) return res; } break; case 'U': { /* decimal, see .writef.p */ WriteFU u = va_arg(args, WriteFU); res = WriteULongest(stream, (ULongest)u, 10, 0); if (res != ResOK) return res; } break; case '3': { /* decimal for thousandths */ WriteFU u = va_arg(args, WriteFU); res = WriteULongest(stream, (ULongest)u, 10, 3); if (res != ResOK) return res; } break; case 'B': { /* binary, see .writef.p */ WriteFB b = va_arg(args, WriteFB); res = WriteULongest(stream, (ULongest)b, 2, sizeof(WriteFB) * CHAR_BIT); if (res != ResOK) return res; } break; case '$': { /* dollar char */ r = mps_lib_fputc('$', stream); if (r == mps_lib_EOF) return ResIO; } break; case 'D': { /* double */ WriteFD d = va_arg(args, WriteFD); res = WriteDouble(stream, d); if (res != ResOK) return res; } break; default: NOTREACHED; } } ++format; } format = va_arg(args, const char *); } return ResOK; }
static Res WriteDouble(mps_lib_FILE *stream, double d) { double F = d; int E = 0, i, x = 0; /* Largest exponent that will print in %f style. Larger will use %e */ /* style. DBL_DIG is chosen for use of doubles as extra-large integers. */ int expmax = DBL_DIG; /* Smallest exponent that will print in %f style. Smaller will use */ /* %e style. -4 is chosen because it is the %g default. */ int expmin = -4; /* Epsilon defines how many digits will be printed. Using DBL_EPSILON */ /* prints all the significant digits. To print fewer digits, set */ /* epsilon to 10 ^ - N, where N is the desired number of digits. */ double epsilon = DBL_EPSILON / 2; char digits[] = "0123456789"; /* sign, DBL_DIG, '0.', 'e', '+/-', log10(DBL_MAX_10_EXP), */ /* terminator. See .write.double.check. */ char buf[1+DBL_DIG+2+1+1+DBL_DIG+1]; int j = 0; if (F == 0.0) { if (mps_lib_fputs("0", stream) == mps_lib_EOF) return ResIO; return ResOK; } if (F < 0) { buf[j] = '-'; j++; F = - F; } /* This scaling operation could introduce rounding errors. */ for ( ; F >= 1.0 ; F /= 10.0) { E++; if (E > DBL_MAX_10_EXP) { if (mps_lib_fputs("Infinity", stream) == mps_lib_EOF) return ResIO; return ResOK; } } for ( ; F < 0.1; F *= 10) E--; /* See if %e notation is required */ if (E > expmax || E <= expmin) { x = E - 1; E = 1; } /* Insert leading 0's */ if (E <= 0) { buf[j] = '0'; j++; } if (E < 0) { buf[j] = '.'; j++; } for (i = -E; i > 0; i--) { buf[j] = '0'; j++; } /* Convert the fraction to base 10, inserting a decimal according to */ /* the exponent. This is Steele and White's FP3 algorithm. */ do { int U; if (E == 0) { buf[j] = '.'; j++; } F *= 10.0; U = (int)F; F = F - U; epsilon *= 10.0; E--; if (F < epsilon || F > 1.0 - epsilon) { if (F < 0.5) buf[j] = digits[U]; else buf[j] = digits[U + 1]; j++; break; } buf[j] = digits[U]; j++; } while (1); /* Insert trailing 0's */ for (i = E; i > 0; i--) { buf[j] = '0'; j++; } /* If %e notation is selected, append the exponent indicator and sign. */ if (x != 0) { buf[j] = 'e'; j++; if (x < 0) { buf[j] = '-'; j++; x = - x; } else { buf[j] = '+'; j++; } /* Format the exponent to at least two digits. */ for (i = 100; i <= x; ) i *= 10; i /= 10; do { buf[j] = digits[x / i]; j++; x %= i; i /= 10; } while (i > 0); } buf[j] = '\0'; /* arnold */ if (mps_lib_fputs(buf, stream) == mps_lib_EOF) return ResIO; return ResOK; }
Res WriteF(mps_lib_FILE *stream, ...) { const char *format; int r; size_t i; Res res; va_list args; AVER(stream != NULL); va_start(args, stream); for(;;) { format = va_arg(args, const char *); if (format == NULL) break; while(*format != '\0') { if (*format != '$') { r = mps_lib_fputc(*format, stream); /* Could be more efficient */ if (r == mps_lib_EOF) return ResIO; } else { ++format; AVER(*format != '\0'); switch(*format) { case 'A': { /* address */ WriteFA addr = va_arg(args, WriteFA); res = WriteWord(stream, (Word)addr, 16, (sizeof(WriteFA) * CHAR_BIT + 3) / 4); if (res != ResOK) return res; } break; case 'P': { /* pointer, see .writef.p */ WriteFP p = va_arg(args, WriteFP); res = WriteWord(stream, (Word)p, 16, (sizeof(WriteFP) * CHAR_BIT + 3)/ 4); if (res != ResOK) return res; } break; case 'F': { /* function */ WriteFF f = va_arg(args, WriteFF); WriteFF *fp = &f; /* dodge to placate splint */ Byte *b = *((Byte **)&fp); for(i=0; i < sizeof(WriteFF); i++) { res = WriteWord(stream, (Word)(b[i]), 16, (CHAR_BIT + 3) / 4); if (res != ResOK) return res; } } break; case 'S': { /* string */ WriteFS s = va_arg(args, WriteFS); r = mps_lib_fputs((const char *)s, stream); if (r == mps_lib_EOF) return ResIO; } break; case 'C': { /* character */ WriteFC c = va_arg(args, WriteFC); /* promoted */ r = mps_lib_fputc((int)c, stream); if (r == mps_lib_EOF) return ResIO; } break; case 'W': { /* word */ WriteFW w = va_arg(args, WriteFW); res = WriteWord(stream, (Word)w, 16, (sizeof(WriteFW) * CHAR_BIT + 3) / 4); if (res != ResOK) return res; } break; case 'U': { /* decimal, see .writef.p */ WriteFU u = va_arg(args, WriteFU); res = WriteWord(stream, (Word)u, 10, 0); if (res != ResOK) return res; } break; case 'B': { /* binary, see .writef.p */ WriteFB b = va_arg(args, WriteFB); res = WriteWord(stream, (Word)b, 2, sizeof(WriteFB) * CHAR_BIT); if (res != ResOK) return res; } break; case '$': { /* dollar char */ r = mps_lib_fputc('$', stream); if (r == mps_lib_EOF) return ResIO; } break; case 'D': { /* double */ WriteFD d = va_arg(args, WriteFD); res = WriteDouble(stream, d); if (res != ResOK) return res; } break; default: NOTREACHED; } } ++format; } } va_end(args); return ResOK; }