diff options
Diffstat (limited to 'gs/psi/igcstr.c')
-rw-r--r-- | gs/psi/igcstr.c | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/gs/psi/igcstr.c b/gs/psi/igcstr.c new file mode 100644 index 000000000..86881836c --- /dev/null +++ b/gs/psi/igcstr.c @@ -0,0 +1,438 @@ +/* Copyright (C) 2001-2006 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, modified + or distributed except as expressly authorized under the terms of that + license. Refer to licensing information at http://www.artifex.com/ + or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, + San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. +*/ + +/* $Id$ */ +/* String GC routines for Ghostscript */ +#include "memory_.h" +#include "ghost.h" +#include "gsmdebug.h" +#include "gsstruct.h" +#include "iastate.h" +#include "igcstr.h" + +/* Forward references */ +static bool gc_mark_string(const byte *, uint, bool, const chunk_t *); + +/* (Un)mark the strings in a chunk. */ +void +gc_strings_set_marks(chunk_t * cp, bool mark) +{ + if (cp->smark != 0) { + if_debug3('6', "[6]clearing string marks 0x%lx[%u] to %d\n", + (ulong) cp->smark, cp->smark_size, (int)mark); + memset(cp->smark, 0, cp->smark_size); + if (mark) + gc_mark_string(cp->sbase, cp->climit - cp->sbase, true, cp); + } +} + +/* We mark strings a word at a time. */ +typedef string_mark_unit bword; + +#define bword_log2_bytes log2_sizeof_string_mark_unit +#define bword_bytes (1 << bword_log2_bytes) +#define bword_log2_bits (bword_log2_bytes + 3) +#define bword_bits (1 << bword_log2_bits) +#define bword_1s (~(bword)0) +/* Compensate for byte order reversal if necessary. */ +#if arch_is_big_endian +# if bword_bytes == 2 +# define bword_swap_bytes(m) m = (m << 8) | (m >> 8) +# else /* bword_bytes == 4 */ +# define bword_swap_bytes(m)\ + m = (m << 24) | ((m & 0xff00) << 8) | ((m >> 8) & 0xff00) | (m >> 24) +# endif +#else +# define bword_swap_bytes(m) DO_NOTHING +#endif + +/* (Un)mark a string in a known chunk. Return true iff any new marks. */ +static bool +gc_mark_string(const byte * ptr, uint size, bool set, const chunk_t * cp) +{ + uint offset = ptr - cp->sbase; + bword *bp = (bword *) (cp->smark + ((offset & -bword_bits) >> 3)); + uint bn = offset & (bword_bits - 1); + bword m = bword_1s << bn; + uint left = size; + bword marks = 0; + + bword_swap_bytes(m); + if (set) { + if (left + bn >= bword_bits) { + marks |= ~*bp & m; + *bp |= m; + m = bword_1s, left -= bword_bits - bn, bp++; + while (left >= bword_bits) { + marks |= ~*bp; + *bp = bword_1s; + left -= bword_bits, bp++; + } + } + if (left) { + bword_swap_bytes(m); + m -= m << left; + bword_swap_bytes(m); + marks |= ~*bp & m; + *bp |= m; + } + } else { + if (left + bn >= bword_bits) { + *bp &= ~m; + m = bword_1s, left -= bword_bits - bn, bp++; + if (left >= bword_bits * 5) { + memset(bp, 0, (left & -bword_bits) >> 3); + bp += left >> bword_log2_bits; + left &= bword_bits - 1; + } else + while (left >= bword_bits) { + *bp = 0; + left -= bword_bits, bp++; + } + } + if (left) { + bword_swap_bytes(m); + m -= m << left; + bword_swap_bytes(m); + *bp &= ~m; + } + } + return marks != 0; +} + +/* Print a string for debugging. We need this because there is no d--- + * equivalent of fwrite. + */ +static void +dfwrite(const byte *ptr, uint count) +{ + uint i; + for (i = 0; i < count; ++i) + dputc(ptr[i]); +} + +/* Mark a string. Return true if any new marks. */ +bool +gc_string_mark(const byte * ptr, uint size, bool set, gc_state_t * gcst) +{ + const chunk_t *cp; + bool marks; + + if (size == 0) + return false; +#define dprintstr()\ + dputc('('); dfwrite(ptr, min(size, 20));\ + dputs((size <= 20 ? ")" : "...)")) + if (!(cp = gc_locate(ptr, gcst))) { /* not in a chunk */ +#ifdef DEBUG + if (gs_debug_c('5')) { + dlprintf2("[5]0x%lx[%u]", (ulong) ptr, size); + dprintstr(); + dputs(" not in a chunk\n"); + } +#endif + return false; + } + if (cp->smark == 0) /* not marking strings */ + return false; +#ifdef DEBUG + if (ptr < cp->ctop) { + lprintf4("String pointer 0x%lx[%u] outside [0x%lx..0x%lx)\n", + (ulong) ptr, size, (ulong) cp->ctop, (ulong) cp->climit); + return false; + } else if (ptr + size > cp->climit) { /* + * If this is the bottommost string in a chunk that has + * an inner chunk, the string's starting address is both + * cp->ctop of the outer chunk and cp->climit of the inner; + * gc_locate may incorrectly attribute the string to the + * inner chunk because of this. This doesn't affect + * marking or relocation, since the machinery for these + * is all associated with the outermost chunk, + * but it can cause the validity check to fail. + * Check for this case now. + */ + const chunk_t *scp = cp; + + while (ptr == scp->climit && scp->outer != 0) + scp = scp->outer; + if (ptr + size > scp->climit) { + lprintf4("String pointer 0x%lx[%u] outside [0x%lx..0x%lx)\n", + (ulong) ptr, size, + (ulong) scp->ctop, (ulong) scp->climit); + return false; + } + } +#endif + marks = gc_mark_string(ptr, size, set, cp); +#ifdef DEBUG + if (gs_debug_c('5')) { + dlprintf4("[5]%s%smarked 0x%lx[%u]", + (marks ? "" : "already "), (set ? "" : "un"), + (ulong) ptr, size); + dprintstr(); + dputc('\n'); + } +#endif + return marks; +} + +/* Clear the relocation for strings. */ +/* This requires setting the marks. */ +void +gc_strings_clear_reloc(chunk_t * cp) +{ + if (cp->sreloc != 0) { + gc_strings_set_marks(cp, true); + if_debug1('6', "[6]clearing string reloc 0x%lx\n", + (ulong) cp->sreloc); + gc_strings_set_reloc(cp); + } +} + +/* Count the 0-bits in a byte. */ +static const byte count_zero_bits_table[256] = +{ +#define o4(n) n,n-1,n-1,n-2 +#define o16(n) o4(n),o4(n-1),o4(n-1),o4(n-2) +#define o64(n) o16(n),o16(n-1),o16(n-1),o16(n-2) + o64(8), o64(7), o64(7), o64(6) +}; + +#define byte_count_zero_bits(byt)\ + (uint)(count_zero_bits_table[byt]) +#define byte_count_one_bits(byt)\ + (uint)(8 - count_zero_bits_table[byt]) + +/* Set the relocation for the strings in a chunk. */ +/* The sreloc table stores the relocated offset from climit for */ +/* the beginning of each block of string_data_quantum characters. */ +void +gc_strings_set_reloc(chunk_t * cp) +{ + if (cp->sreloc != 0 && cp->smark != 0) { + byte *bot = cp->ctop; + byte *top = cp->climit; + uint count = + (top - bot + (string_data_quantum - 1)) >> + log2_string_data_quantum; + string_reloc_offset *relp = + cp->sreloc + + (cp->smark_size >> (log2_string_data_quantum - 3)); + register const byte *bitp = cp->smark + cp->smark_size; + register string_reloc_offset reloc = 0; + + /* Skip initial unrelocated strings quickly. */ +#if string_data_quantum == bword_bits || string_data_quantum == bword_bits * 2 + { + /* Work around the alignment aliasing bug. */ + const bword *wp = (const bword *)bitp; + +#if string_data_quantum == bword_bits +# define RELOC_TEST_1S(wp) (wp[-1]) +#else /* string_data_quantum == bword_bits * 2 */ +# define RELOC_TEST_1S(wp) (wp[-1] & wp[-2]) +#endif + while (count && RELOC_TEST_1S(wp) == bword_1s) { + wp -= string_data_quantum / bword_bits; + *--relp = reloc += string_data_quantum; + --count; + } +#undef RELOC_TEST_1S + bitp = (const byte *)wp; + } +#endif + while (count--) { + bitp -= string_data_quantum / 8; + reloc += string_data_quantum - + byte_count_zero_bits(bitp[0]); + reloc -= byte_count_zero_bits(bitp[1]); + reloc -= byte_count_zero_bits(bitp[2]); + reloc -= byte_count_zero_bits(bitp[3]); +#if log2_string_data_quantum > 5 + reloc -= byte_count_zero_bits(bitp[4]); + reloc -= byte_count_zero_bits(bitp[5]); + reloc -= byte_count_zero_bits(bitp[6]); + reloc -= byte_count_zero_bits(bitp[7]); +#endif + *--relp = reloc; + } + } + cp->sdest = cp->climit; +} + +/* Relocate a string pointer. */ +void +igc_reloc_string(gs_string * sptr, gc_state_t * gcst) +{ + byte *ptr; + const chunk_t *cp; + uint offset; + uint reloc; + const byte *bitp; + byte byt; + + if (sptr->size == 0) { + sptr->data = 0; + return; + } + ptr = sptr->data; + if (!(cp = gc_locate(ptr, gcst))) /* not in a chunk */ + return; + if (cp->sreloc == 0 || cp->smark == 0) /* not marking strings */ + return; + offset = ptr - cp->sbase; + reloc = cp->sreloc[offset >> log2_string_data_quantum]; + bitp = &cp->smark[offset >> 3]; + switch (offset & (string_data_quantum - 8)) { +#if log2_string_data_quantum > 5 + case 56: + reloc -= byte_count_one_bits(bitp[-7]); + case 48: + reloc -= byte_count_one_bits(bitp[-6]); + case 40: + reloc -= byte_count_one_bits(bitp[-5]); + case 32: + reloc -= byte_count_one_bits(bitp[-4]); +#endif + case 24: + reloc -= byte_count_one_bits(bitp[-3]); + case 16: + reloc -= byte_count_one_bits(bitp[-2]); + case 8: + reloc -= byte_count_one_bits(bitp[-1]); + } + byt = *bitp & (0xff >> (8 - (offset & 7))); + reloc -= byte_count_one_bits(byt); + if_debug2('5', "[5]relocate string 0x%lx to 0x%lx\n", + (ulong) ptr, (ulong) (cp->sdest - reloc)); + sptr->data = cp->sdest - reloc; +} +void +igc_reloc_const_string(gs_const_string * sptr, gc_state_t * gcst) +{ /* We assume the representation of byte * and const byte * is */ + /* the same.... */ + igc_reloc_string((gs_string *) sptr, gcst); +} +void +igc_reloc_param_string(gs_param_string * sptr, gc_state_t * gcst) +{ + if (!sptr->persistent) { + /* We assume that gs_param_string is a subclass of gs_string. */ + igc_reloc_string((gs_string *)sptr, gcst); + } +} + +/* Compact the strings in a chunk. */ +void +gc_strings_compact(chunk_t * cp) +{ + if (cp->smark != 0) { + byte *hi = cp->climit; + byte *lo = cp->ctop; + const byte *from = hi; + byte *to = hi; + const byte *bp = cp->smark + cp->smark_size; + +#ifdef DEBUG + if (gs_debug_c('4') || gs_debug_c('5')) { + byte *base = cp->sbase; + uint i = (lo - base) & -string_data_quantum; + uint n = ROUND_UP(hi - base, string_data_quantum); + +#define R 16 + for (; i < n; i += R) { + uint j; + + dlprintf1("[4]0x%lx: ", (ulong) (base + i)); + for (j = i; j < i + R; j++) { + byte ch = base[j]; + + if (ch <= 31) { + dputc('^'); + dputc(ch + 0100); + } else + dputc(ch); + } + dputc(' '); + for (j = i; j < i + R; j++) + dputc((cp->smark[j >> 3] & (1 << (j & 7)) ? + '+' : '.')); +#undef R + if (!(i & (string_data_quantum - 1))) + dprintf1(" %u", cp->sreloc[i >> log2_string_data_quantum]); + dputc('\n'); + } + } +#endif + /* + * Skip unmodified strings quickly. We know that cp->smark is + * aligned to a string_mark_unit. + */ + { + /* Work around the alignment aliasing bug. */ + const bword *wp = (const bword *)bp; + + while (to > lo && wp[-1] == bword_1s) + to -= bword_bits, --wp; + bp = (const byte *)wp; + while (to > lo && bp[-1] == 0xff) + to -= 8, --bp; + } + from = to; + while (from > lo) { + byte b = *--bp; + + from -= 8; + switch (b) { + case 0xff: + to -= 8; + /* + * Since we've seen a byte other than 0xff, we know + * to != from at this point. + */ + to[7] = from[7]; + to[6] = from[6]; + to[5] = from[5]; + to[4] = from[4]; + to[3] = from[3]; + to[2] = from[2]; + to[1] = from[1]; + to[0] = from[0]; + break; + default: + if (b & 0x80) + *--to = from[7]; + if (b & 0x40) + *--to = from[6]; + if (b & 0x20) + *--to = from[5]; + if (b & 0x10) + *--to = from[4]; + if (b & 8) + *--to = from[3]; + if (b & 4) + *--to = from[2]; + if (b & 2) + *--to = from[1]; + if (b & 1) + *--to = from[0]; + /* falls through */ + case 0: + ; + } + } + gs_alloc_fill(cp->ctop, gs_alloc_fill_collected, + to - cp->ctop); + cp->ctop = to; + } +} |