xref: /plan9-contrib/sys/src/cmd/gs/src/iname.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1989, 1995, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: iname.c,v 1.7 2003/09/03 03:22:59 giles Exp $ */
187dd7cddfSDavid du Colombier /* Name lookup for Ghostscript interpreter */
197dd7cddfSDavid du Colombier #include "memory_.h"
207dd7cddfSDavid du Colombier #include "string_.h"
217dd7cddfSDavid du Colombier #include "ghost.h"
227dd7cddfSDavid du Colombier #include "gsstruct.h"
237dd7cddfSDavid du Colombier #include "gxobj.h"		/* for o_set_unmarked */
24*593dc095SDavid du Colombier #include "ierrors.h"
257dd7cddfSDavid du Colombier #include "inamedef.h"
267dd7cddfSDavid du Colombier #include "imemory.h"		/* for isave.h */
277dd7cddfSDavid du Colombier #include "isave.h"
287dd7cddfSDavid du Colombier #include "store.h"
297dd7cddfSDavid du Colombier 
307dd7cddfSDavid du Colombier /* Public values */
317dd7cddfSDavid du Colombier const uint name_max_string = max_name_string;
327dd7cddfSDavid du Colombier 
337dd7cddfSDavid du Colombier /* Define the permutation table for name hashing. */
347dd7cddfSDavid du Colombier private const byte hash_permutation[256] = {
357dd7cddfSDavid du Colombier     NAME_HASH_PERMUTATION_DATA
367dd7cddfSDavid du Colombier };
377dd7cddfSDavid du Colombier 
387dd7cddfSDavid du Colombier /* Define the data for the 1-character names. */
397dd7cddfSDavid du Colombier private const byte nt_1char_names[NT_1CHAR_SIZE] = {
407dd7cddfSDavid du Colombier     NT_1CHAR_NAMES_DATA
417dd7cddfSDavid du Colombier };
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier /* Structure descriptors */
447dd7cddfSDavid du Colombier gs_private_st_simple(st_name_sub_table, name_sub_table, "name_sub_table");
457dd7cddfSDavid du Colombier gs_private_st_composite(st_name_string_sub_table, name_string_sub_table_t,
467dd7cddfSDavid du Colombier 			"name_string_sub_table_t",
477dd7cddfSDavid du Colombier 			name_string_sub_enum_ptrs, name_string_sub_reloc_ptrs);
487dd7cddfSDavid du Colombier gs_private_st_composite(st_name_table, name_table, "name_table",
497dd7cddfSDavid du Colombier 			name_table_enum_ptrs, name_table_reloc_ptrs);
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier /* Forward references */
52*593dc095SDavid du Colombier private int name_alloc_sub(name_table *);
53*593dc095SDavid du Colombier private void name_free_sub(name_table *, uint);
54*593dc095SDavid du Colombier private void name_scan_sub(name_table *, uint, bool);
557dd7cddfSDavid du Colombier 
567dd7cddfSDavid du Colombier /* Debugging printout */
577dd7cddfSDavid du Colombier #ifdef DEBUG
587dd7cddfSDavid du Colombier private void
name_print(const char * msg,const name_table * nt,uint nidx,const int * pflag)597dd7cddfSDavid du Colombier name_print(const char *msg, const name_table *nt, uint nidx, const int *pflag)
607dd7cddfSDavid du Colombier {
617dd7cddfSDavid du Colombier     const name_string_t *pnstr = names_index_string_inline(nt, nidx);
627dd7cddfSDavid du Colombier     const name *pname = names_index_ptr_inline(nt, nidx);
637dd7cddfSDavid du Colombier     const byte *str = pnstr->string_bytes;
647dd7cddfSDavid du Colombier 
657dd7cddfSDavid du Colombier     dlprintf1("[n]%s", msg);
667dd7cddfSDavid du Colombier     if (pflag)
677dd7cddfSDavid du Colombier 	dprintf1("(%d)", *pflag);
687dd7cddfSDavid du Colombier     dprintf2(" (0x%lx#%u)", (ulong)pname, nidx);
697dd7cddfSDavid du Colombier     debug_print_string(str, pnstr->string_size);
707dd7cddfSDavid du Colombier     dprintf2("(0x%lx,%u)\n", (ulong)str, pnstr->string_size);
717dd7cddfSDavid du Colombier }
727dd7cddfSDavid du Colombier #  define if_debug_name(msg, nt, nidx, pflag)\
737dd7cddfSDavid du Colombier      if ( gs_debug_c('n') ) name_print(msg, nt, nidx, pflag)
747dd7cddfSDavid du Colombier #else
757dd7cddfSDavid du Colombier #  define if_debug_name(msg, nt, nidx, pflag) DO_NOTHING
767dd7cddfSDavid du Colombier #endif
777dd7cddfSDavid du Colombier 
787dd7cddfSDavid du Colombier /* Initialize a name table */
797dd7cddfSDavid du Colombier name_table *
names_init(ulong count,gs_ref_memory_t * imem)807dd7cddfSDavid du Colombier names_init(ulong count, gs_ref_memory_t *imem)
817dd7cddfSDavid du Colombier {
827dd7cddfSDavid du Colombier     gs_memory_t *mem = (gs_memory_t *)imem;
837dd7cddfSDavid du Colombier     name_table *nt;
847dd7cddfSDavid du Colombier     int i;
857dd7cddfSDavid du Colombier 
867dd7cddfSDavid du Colombier     if (count == 0)
877dd7cddfSDavid du Colombier 	count = max_name_count + 1L;
887dd7cddfSDavid du Colombier     else if (count - 1 > max_name_count)
897dd7cddfSDavid du Colombier 	return 0;
907dd7cddfSDavid du Colombier     nt = gs_alloc_struct(mem, name_table, &st_name_table, "name_init(nt)");
917dd7cddfSDavid du Colombier     if (nt == 0)
927dd7cddfSDavid du Colombier 	return 0;
937dd7cddfSDavid du Colombier     memset(nt, 0, sizeof(name_table));
947dd7cddfSDavid du Colombier     nt->max_sub_count =
957dd7cddfSDavid du Colombier 	((count - 1) | nt_sub_index_mask) >> nt_log2_sub_size;
967dd7cddfSDavid du Colombier     nt->name_string_attrs = imemory_space(imem) | a_readonly;
977dd7cddfSDavid du Colombier     nt->memory = mem;
987dd7cddfSDavid du Colombier     /* Initialize the one-character names. */
997dd7cddfSDavid du Colombier     /* Start by creating the necessary sub-tables. */
1007dd7cddfSDavid du Colombier     for (i = 0; i < NT_1CHAR_FIRST + NT_1CHAR_SIZE; i += nt_sub_size) {
1017dd7cddfSDavid du Colombier 	int code = name_alloc_sub(nt);
1027dd7cddfSDavid du Colombier 
1037dd7cddfSDavid du Colombier 	if (code < 0) {
1047dd7cddfSDavid du Colombier 	    while (nt->sub_next > 0)
1057dd7cddfSDavid du Colombier 		name_free_sub(nt, --(nt->sub_next));
1067dd7cddfSDavid du Colombier 	    gs_free_object(mem, nt, "name_init(nt)");
1077dd7cddfSDavid du Colombier 	    return 0;
1087dd7cddfSDavid du Colombier 	}
1097dd7cddfSDavid du Colombier     }
1107dd7cddfSDavid du Colombier     for (i = -1; i < NT_1CHAR_SIZE; i++) {
1117dd7cddfSDavid du Colombier 	uint ncnt = NT_1CHAR_FIRST + i;
1127dd7cddfSDavid du Colombier 	uint nidx = name_count_to_index(ncnt);
1137dd7cddfSDavid du Colombier 	name *pname = names_index_ptr_inline(nt, nidx);
1147dd7cddfSDavid du Colombier 	name_string_t *pnstr = names_index_string_inline(nt, nidx);
1157dd7cddfSDavid du Colombier 
1167dd7cddfSDavid du Colombier 	if (i < 0)
1177dd7cddfSDavid du Colombier 	    pnstr->string_bytes = nt_1char_names,
1187dd7cddfSDavid du Colombier 		pnstr->string_size = 0;
1197dd7cddfSDavid du Colombier 	else
1207dd7cddfSDavid du Colombier 	    pnstr->string_bytes = nt_1char_names + i,
1217dd7cddfSDavid du Colombier 		pnstr->string_size = 1;
1227dd7cddfSDavid du Colombier 	pnstr->foreign_string = 1;
1237dd7cddfSDavid du Colombier 	pnstr->mark = 1;
1247dd7cddfSDavid du Colombier 	pname->pvalue = pv_no_defn;
1257dd7cddfSDavid du Colombier     }
1267dd7cddfSDavid du Colombier     nt->perm_count = NT_1CHAR_FIRST + NT_1CHAR_SIZE;
1277dd7cddfSDavid du Colombier     /* Reconstruct the free list. */
1287dd7cddfSDavid du Colombier     nt->free = 0;
1297dd7cddfSDavid du Colombier     names_trace_finish(nt, NULL);
1307dd7cddfSDavid du Colombier     return nt;
1317dd7cddfSDavid du Colombier }
1327dd7cddfSDavid du Colombier 
1337dd7cddfSDavid du Colombier /* Get the allocator for the name table. */
1347dd7cddfSDavid du Colombier gs_memory_t *
names_memory(const name_table * nt)1357dd7cddfSDavid du Colombier names_memory(const name_table * nt)
1367dd7cddfSDavid du Colombier {
1377dd7cddfSDavid du Colombier     return nt->memory;
1387dd7cddfSDavid du Colombier }
1397dd7cddfSDavid du Colombier 
1407dd7cddfSDavid du Colombier /* Look up or enter a name in the table. */
1417dd7cddfSDavid du Colombier /* Return 0 or an error code. */
1427dd7cddfSDavid du Colombier /* The return may overlap the characters of the string! */
1437dd7cddfSDavid du Colombier /* See iname.h for the meaning of enterflag. */
1447dd7cddfSDavid du Colombier int
names_ref(name_table * nt,const byte * ptr,uint size,ref * pref,int enterflag)1457dd7cddfSDavid du Colombier names_ref(name_table *nt, const byte *ptr, uint size, ref *pref, int enterflag)
1467dd7cddfSDavid du Colombier {
1477dd7cddfSDavid du Colombier     name *pname;
1487dd7cddfSDavid du Colombier     name_string_t *pnstr;
1497dd7cddfSDavid du Colombier     uint nidx;
1507dd7cddfSDavid du Colombier     uint *phash;
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier     /* Compute a hash for the string. */
1537dd7cddfSDavid du Colombier     /* Make a special check for 1-character names. */
1547dd7cddfSDavid du Colombier     switch (size) {
1557dd7cddfSDavid du Colombier     case 0:
1567dd7cddfSDavid du Colombier 	nidx = name_count_to_index(1);
1577dd7cddfSDavid du Colombier 	pname = names_index_ptr_inline(nt, nidx);
1587dd7cddfSDavid du Colombier 	goto mkn;
1597dd7cddfSDavid du Colombier     case 1:
1607dd7cddfSDavid du Colombier 	if (*ptr < NT_1CHAR_SIZE) {
1617dd7cddfSDavid du Colombier 	    uint hash = *ptr + NT_1CHAR_FIRST;
1627dd7cddfSDavid du Colombier 
1637dd7cddfSDavid du Colombier 	    nidx = name_count_to_index(hash);
1647dd7cddfSDavid du Colombier 	    pname = names_index_ptr_inline(nt, nidx);
1657dd7cddfSDavid du Colombier 	    goto mkn;
1667dd7cddfSDavid du Colombier 	}
1677dd7cddfSDavid du Colombier 	/* falls through */
1687dd7cddfSDavid du Colombier     default: {
1697dd7cddfSDavid du Colombier 	uint hash;
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier 	NAME_HASH(hash, hash_permutation, ptr, size);
1727dd7cddfSDavid du Colombier 	phash = nt->hash + (hash & (NT_HASH_SIZE - 1));
1737dd7cddfSDavid du Colombier     }
1747dd7cddfSDavid du Colombier     }
1757dd7cddfSDavid du Colombier 
1767dd7cddfSDavid du Colombier     for (nidx = *phash; nidx != 0;
1777dd7cddfSDavid du Colombier 	 nidx = name_next_index(nidx, pnstr)
1787dd7cddfSDavid du Colombier 	) {
1797dd7cddfSDavid du Colombier 	pnstr = names_index_string_inline(nt, nidx);
1807dd7cddfSDavid du Colombier 	if (pnstr->string_size == size &&
1817dd7cddfSDavid du Colombier 	    !memcmp_inline(ptr, pnstr->string_bytes, size)
1827dd7cddfSDavid du Colombier 	    ) {
1837dd7cddfSDavid du Colombier 	    pname = name_index_ptr_inline(nt, nidx);
1847dd7cddfSDavid du Colombier 	    goto mkn;
1857dd7cddfSDavid du Colombier 	}
1867dd7cddfSDavid du Colombier     }
1877dd7cddfSDavid du Colombier     /* Name was not in the table.  Make a new entry. */
1887dd7cddfSDavid du Colombier     if (enterflag < 0)
1897dd7cddfSDavid du Colombier 	return_error(e_undefined);
1907dd7cddfSDavid du Colombier     if (size > max_name_string)
1917dd7cddfSDavid du Colombier 	return_error(e_limitcheck);
1927dd7cddfSDavid du Colombier     nidx = nt->free;
1937dd7cddfSDavid du Colombier     if (nidx == 0) {
1947dd7cddfSDavid du Colombier 	int code = name_alloc_sub(nt);
1957dd7cddfSDavid du Colombier 
1967dd7cddfSDavid du Colombier 	if (code < 0)
1977dd7cddfSDavid du Colombier 	    return code;
1987dd7cddfSDavid du Colombier 	nidx = nt->free;
1997dd7cddfSDavid du Colombier     }
2007dd7cddfSDavid du Colombier     pnstr = names_index_string_inline(nt, nidx);
2017dd7cddfSDavid du Colombier     if (enterflag == 1) {
2027dd7cddfSDavid du Colombier 	byte *cptr = (byte *)gs_alloc_string(nt->memory, size,
2037dd7cddfSDavid du Colombier 					     "names_ref(string)");
2047dd7cddfSDavid du Colombier 
2057dd7cddfSDavid du Colombier 	if (cptr == 0)
2067dd7cddfSDavid du Colombier 	    return_error(e_VMerror);
2077dd7cddfSDavid du Colombier 	memcpy(cptr, ptr, size);
2087dd7cddfSDavid du Colombier 	pnstr->string_bytes = cptr;
2097dd7cddfSDavid du Colombier 	pnstr->foreign_string = 0;
2107dd7cddfSDavid du Colombier     } else {
2117dd7cddfSDavid du Colombier 	pnstr->string_bytes = ptr;
2127dd7cddfSDavid du Colombier 	pnstr->foreign_string = (enterflag == 0 ? 1 : 0);
2137dd7cddfSDavid du Colombier     }
2147dd7cddfSDavid du Colombier     pnstr->string_size = size;
2157dd7cddfSDavid du Colombier     pname = name_index_ptr_inline(nt, nidx);
2167dd7cddfSDavid du Colombier     pname->pvalue = pv_no_defn;
2177dd7cddfSDavid du Colombier     nt->free = name_next_index(nidx, pnstr);
2187dd7cddfSDavid du Colombier     set_name_next_index(nidx, pnstr, *phash);
2197dd7cddfSDavid du Colombier     *phash = nidx;
2207dd7cddfSDavid du Colombier     if_debug_name("new name", nt, nidx, &enterflag);
2217dd7cddfSDavid du Colombier  mkn:
2227dd7cddfSDavid du Colombier     make_name(pref, nidx, pname);
2237dd7cddfSDavid du Colombier     return 0;
2247dd7cddfSDavid du Colombier }
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier /* Get the string for a name. */
2277dd7cddfSDavid du Colombier void
names_string_ref(const name_table * nt,const ref * pnref,ref * psref)2287dd7cddfSDavid du Colombier names_string_ref(const name_table * nt, const ref * pnref /* t_name */ ,
2297dd7cddfSDavid du Colombier 		 ref * psref /* result, t_string */ )
2307dd7cddfSDavid du Colombier {
2317dd7cddfSDavid du Colombier     const name_string_t *pnstr = names_string_inline(nt, pnref);
2327dd7cddfSDavid du Colombier 
2337dd7cddfSDavid du Colombier     make_const_string(psref,
2347dd7cddfSDavid du Colombier 		      (pnstr->foreign_string ? avm_foreign | a_readonly :
2357dd7cddfSDavid du Colombier 		       nt->name_string_attrs),
2367dd7cddfSDavid du Colombier 		      pnstr->string_size,
2377dd7cddfSDavid du Colombier 		      (const byte *)pnstr->string_bytes);
2387dd7cddfSDavid du Colombier }
2397dd7cddfSDavid du Colombier 
2407dd7cddfSDavid du Colombier /* Convert a t_string object to a name. */
2417dd7cddfSDavid du Colombier /* Copy the executable attribute. */
2427dd7cddfSDavid du Colombier int
names_from_string(name_table * nt,const ref * psref,ref * pnref)2437dd7cddfSDavid du Colombier names_from_string(name_table * nt, const ref * psref, ref * pnref)
2447dd7cddfSDavid du Colombier {
2457dd7cddfSDavid du Colombier     int exec = r_has_attr(psref, a_executable);
2467dd7cddfSDavid du Colombier     int code = names_ref(nt, psref->value.bytes, r_size(psref), pnref, 1);
2477dd7cddfSDavid du Colombier 
2487dd7cddfSDavid du Colombier     if (code < 0)
2497dd7cddfSDavid du Colombier 	return code;
2507dd7cddfSDavid du Colombier     if (exec)
2517dd7cddfSDavid du Colombier 	r_set_attrs(pnref, a_executable);
2527dd7cddfSDavid du Colombier     return code;
2537dd7cddfSDavid du Colombier }
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier /* Enter a (permanently allocated) C string as a name. */
2567dd7cddfSDavid du Colombier int
names_enter_string(name_table * nt,const char * str,ref * pref)2577dd7cddfSDavid du Colombier names_enter_string(name_table * nt, const char *str, ref * pref)
2587dd7cddfSDavid du Colombier {
2597dd7cddfSDavid du Colombier     return names_ref(nt, (const byte *)str, strlen(str), pref, 0);
2607dd7cddfSDavid du Colombier }
2617dd7cddfSDavid du Colombier 
2627dd7cddfSDavid du Colombier /* Invalidate the value cache for a name. */
2637dd7cddfSDavid du Colombier void
names_invalidate_value_cache(name_table * nt,const ref * pnref)2647dd7cddfSDavid du Colombier names_invalidate_value_cache(name_table * nt, const ref * pnref)
2657dd7cddfSDavid du Colombier {
2667dd7cddfSDavid du Colombier     pnref->value.pname->pvalue = pv_other;
2677dd7cddfSDavid du Colombier }
2687dd7cddfSDavid du Colombier 
2697dd7cddfSDavid du Colombier /* Convert between names and indices. */
2707dd7cddfSDavid du Colombier #undef names_index
2717dd7cddfSDavid du Colombier name_index_t
names_index(const name_table * nt,const ref * pnref)2727dd7cddfSDavid du Colombier names_index(const name_table * nt, const ref * pnref)
2737dd7cddfSDavid du Colombier {
2747dd7cddfSDavid du Colombier     return names_index_inline(nt, pnref);
2757dd7cddfSDavid du Colombier }
2767dd7cddfSDavid du Colombier void
names_index_ref(const name_table * nt,name_index_t index,ref * pnref)2777dd7cddfSDavid du Colombier names_index_ref(const name_table * nt, name_index_t index, ref * pnref)
2787dd7cddfSDavid du Colombier {
2797dd7cddfSDavid du Colombier     names_index_ref_inline(nt, index, pnref);
2807dd7cddfSDavid du Colombier }
2817dd7cddfSDavid du Colombier name *
names_index_ptr(const name_table * nt,name_index_t index)2827dd7cddfSDavid du Colombier names_index_ptr(const name_table * nt, name_index_t index)
2837dd7cddfSDavid du Colombier {
2847dd7cddfSDavid du Colombier     return names_index_ptr_inline(nt, index);
2857dd7cddfSDavid du Colombier }
2867dd7cddfSDavid du Colombier 
2877dd7cddfSDavid du Colombier /* Get the index of the next valid name. */
2887dd7cddfSDavid du Colombier /* The argument is 0 or a valid index. */
2897dd7cddfSDavid du Colombier /* Return 0 if there are no more. */
2907dd7cddfSDavid du Colombier name_index_t
names_next_valid_index(name_table * nt,name_index_t nidx)2917dd7cddfSDavid du Colombier names_next_valid_index(name_table * nt, name_index_t nidx)
2927dd7cddfSDavid du Colombier {
2937dd7cddfSDavid du Colombier     const name_string_sub_table_t *ssub =
2947dd7cddfSDavid du Colombier 	nt->sub[nidx >> nt_log2_sub_size].strings;
2957dd7cddfSDavid du Colombier     const name_string_t *pnstr;
2967dd7cddfSDavid du Colombier 
2977dd7cddfSDavid du Colombier     do {
2987dd7cddfSDavid du Colombier 	++nidx;
2997dd7cddfSDavid du Colombier 	if ((nidx & nt_sub_index_mask) == 0)
3007dd7cddfSDavid du Colombier 	    for (;; nidx += nt_sub_size) {
3017dd7cddfSDavid du Colombier 		if ((nidx >> nt_log2_sub_size) >= nt->sub_count)
3027dd7cddfSDavid du Colombier 		    return 0;
3037dd7cddfSDavid du Colombier 		ssub = nt->sub[nidx >> nt_log2_sub_size].strings;
3047dd7cddfSDavid du Colombier 		if (ssub != 0)
3057dd7cddfSDavid du Colombier 		    break;
3067dd7cddfSDavid du Colombier 	    }
3077dd7cddfSDavid du Colombier 	pnstr = &ssub->strings[nidx & nt_sub_index_mask];
3087dd7cddfSDavid du Colombier     }
3097dd7cddfSDavid du Colombier     while (pnstr->string_bytes == 0);
3107dd7cddfSDavid du Colombier     return nidx;
3117dd7cddfSDavid du Colombier }
3127dd7cddfSDavid du Colombier 
3137dd7cddfSDavid du Colombier /* ------ Garbage collection ------ */
3147dd7cddfSDavid du Colombier 
3157dd7cddfSDavid du Colombier /* Unmark all non-permanent names before a garbage collection. */
3167dd7cddfSDavid du Colombier void
names_unmark_all(name_table * nt)3177dd7cddfSDavid du Colombier names_unmark_all(name_table * nt)
3187dd7cddfSDavid du Colombier {
3197dd7cddfSDavid du Colombier     uint si;
3207dd7cddfSDavid du Colombier     name_string_sub_table_t *ssub;
3217dd7cddfSDavid du Colombier 
3227dd7cddfSDavid du Colombier     for (si = 0; si < nt->sub_count; ++si)
3237dd7cddfSDavid du Colombier 	if ((ssub = nt->sub[si].strings) != 0) {
3247dd7cddfSDavid du Colombier 	    uint i;
3257dd7cddfSDavid du Colombier 
3267dd7cddfSDavid du Colombier 	    /* We can make the test much more efficient if we want.... */
3277dd7cddfSDavid du Colombier 	    for (i = 0; i < nt_sub_size; ++i)
3287dd7cddfSDavid du Colombier 		if (name_index_to_count((si << nt_log2_sub_size) + i) >=
3297dd7cddfSDavid du Colombier 		    nt->perm_count)
3307dd7cddfSDavid du Colombier 		    ssub->strings[i].mark = 0;
3317dd7cddfSDavid du Colombier 	}
3327dd7cddfSDavid du Colombier }
3337dd7cddfSDavid du Colombier 
3347dd7cddfSDavid du Colombier /* Mark a name.  Return true if new mark.  We export this so we can mark */
3357dd7cddfSDavid du Colombier /* character names in the character cache. */
3367dd7cddfSDavid du Colombier bool
names_mark_index(name_table * nt,name_index_t nidx)3377dd7cddfSDavid du Colombier names_mark_index(name_table * nt, name_index_t nidx)
3387dd7cddfSDavid du Colombier {
3397dd7cddfSDavid du Colombier     name_string_t *pnstr = names_index_string_inline(nt, nidx);
3407dd7cddfSDavid du Colombier 
3417dd7cddfSDavid du Colombier     if (pnstr->mark)
3427dd7cddfSDavid du Colombier 	return false;
3437dd7cddfSDavid du Colombier     pnstr->mark = 1;
3447dd7cddfSDavid du Colombier     return true;
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier 
3477dd7cddfSDavid du Colombier /* Get the object (sub-table) containing a name. */
3487dd7cddfSDavid du Colombier /* The garbage collector needs this so it can relocate pointers to names. */
3497dd7cddfSDavid du Colombier void /*obj_header_t */ *
names_ref_sub_table(name_table * nt,const ref * pnref)3507dd7cddfSDavid du Colombier names_ref_sub_table(name_table * nt, const ref * pnref)
3517dd7cddfSDavid du Colombier {
3527dd7cddfSDavid du Colombier     /* When this procedure is called, the pointers from the name table */
3537dd7cddfSDavid du Colombier     /* to the sub-tables may or may not have been relocated already, */
3547dd7cddfSDavid du Colombier     /* so we can't use them.  Instead, we have to work backwards from */
3557dd7cddfSDavid du Colombier     /* the name pointer itself. */
3567dd7cddfSDavid du Colombier     return pnref->value.pname - (r_size(pnref) & nt_sub_index_mask);
3577dd7cddfSDavid du Colombier }
3587dd7cddfSDavid du Colombier void /*obj_header_t */ *
names_index_sub_table(name_table * nt,name_index_t index)3597dd7cddfSDavid du Colombier names_index_sub_table(name_table * nt, name_index_t index)
3607dd7cddfSDavid du Colombier {
3617dd7cddfSDavid du Colombier     return nt->sub[index >> nt_log2_sub_size].names;
3627dd7cddfSDavid du Colombier }
3637dd7cddfSDavid du Colombier void /*obj_header_t */ *
names_index_string_sub_table(name_table * nt,name_index_t index)3647dd7cddfSDavid du Colombier names_index_string_sub_table(name_table * nt, name_index_t index)
3657dd7cddfSDavid du Colombier {
3667dd7cddfSDavid du Colombier     return nt->sub[index >> nt_log2_sub_size].strings;
3677dd7cddfSDavid du Colombier }
3687dd7cddfSDavid du Colombier 
3697dd7cddfSDavid du Colombier /*
3707dd7cddfSDavid du Colombier  * Clean up the name table after the trace/mark phase of a garbage
3717dd7cddfSDavid du Colombier  * collection, by removing names that aren't marked.  gcst == NULL indicates
3727dd7cddfSDavid du Colombier  * we're doing this for initialization or restore rather than for a GC.
3737dd7cddfSDavid du Colombier  */
3747dd7cddfSDavid du Colombier void
names_trace_finish(name_table * nt,gc_state_t * gcst)3757dd7cddfSDavid du Colombier names_trace_finish(name_table * nt, gc_state_t * gcst)
3767dd7cddfSDavid du Colombier {
3777dd7cddfSDavid du Colombier     uint *phash = &nt->hash[0];
3787dd7cddfSDavid du Colombier     uint i;
3797dd7cddfSDavid du Colombier 
3807dd7cddfSDavid du Colombier     for (i = 0; i < NT_HASH_SIZE; phash++, i++) {
3817dd7cddfSDavid du Colombier 	name_index_t prev = 0;
3827dd7cddfSDavid du Colombier 	/*
3837dd7cddfSDavid du Colombier 	 * The following initialization is only to pacify compilers:
3847dd7cddfSDavid du Colombier 	 * pnprev is only referenced if prev has been set in the loop,
3857dd7cddfSDavid du Colombier 	 * in which case pnprev is also set.
3867dd7cddfSDavid du Colombier 	 */
3877dd7cddfSDavid du Colombier 	name_string_t *pnprev = 0;
3887dd7cddfSDavid du Colombier 	name_index_t nidx = *phash;
3897dd7cddfSDavid du Colombier 
3907dd7cddfSDavid du Colombier 	while (nidx != 0) {
3917dd7cddfSDavid du Colombier 	    name_string_t *pnstr = names_index_string_inline(nt, nidx);
3927dd7cddfSDavid du Colombier 	    name_index_t next = name_next_index(nidx, pnstr);
3937dd7cddfSDavid du Colombier 
3947dd7cddfSDavid du Colombier 	    if (pnstr->mark) {
3957dd7cddfSDavid du Colombier 		prev = nidx;
3967dd7cddfSDavid du Colombier 		pnprev = pnstr;
3977dd7cddfSDavid du Colombier 	    } else {
3987dd7cddfSDavid du Colombier 		if_debug_name("GC remove name", nt, nidx, NULL);
3997dd7cddfSDavid du Colombier 		/* Zero out the string data for the GC. */
4007dd7cddfSDavid du Colombier 		pnstr->string_bytes = 0;
4017dd7cddfSDavid du Colombier 		pnstr->string_size = 0;
4027dd7cddfSDavid du Colombier 		if (prev == 0)
4037dd7cddfSDavid du Colombier 		    *phash = next;
4047dd7cddfSDavid du Colombier 		else
4057dd7cddfSDavid du Colombier 		    set_name_next_index(prev, pnprev, next);
4067dd7cddfSDavid du Colombier 	    }
4077dd7cddfSDavid du Colombier 	    nidx = next;
4087dd7cddfSDavid du Colombier 	}
4097dd7cddfSDavid du Colombier     }
4107dd7cddfSDavid du Colombier     /* Reconstruct the free list. */
4117dd7cddfSDavid du Colombier     nt->free = 0;
4127dd7cddfSDavid du Colombier     for (i = nt->sub_count; i--;) {
4137dd7cddfSDavid du Colombier 	name_sub_table *sub = nt->sub[i].names;
4147dd7cddfSDavid du Colombier 	name_string_sub_table_t *ssub = nt->sub[i].strings;
4157dd7cddfSDavid du Colombier 
4167dd7cddfSDavid du Colombier 	if (sub != 0) {
4177dd7cddfSDavid du Colombier 	    name_scan_sub(nt, i, true);
4187dd7cddfSDavid du Colombier 	    if (nt->sub[i].names == 0 && gcst != 0) {
4197dd7cddfSDavid du Colombier 		/* Mark the just-freed sub-table as unmarked. */
4207dd7cddfSDavid du Colombier 		o_set_unmarked((obj_header_t *)sub - 1);
4217dd7cddfSDavid du Colombier 		o_set_unmarked((obj_header_t *)ssub - 1);
4227dd7cddfSDavid du Colombier 	    }
4237dd7cddfSDavid du Colombier 	}
4247dd7cddfSDavid du Colombier 	if (i == 0)
4257dd7cddfSDavid du Colombier 	    break;
4267dd7cddfSDavid du Colombier     }
4277dd7cddfSDavid du Colombier     nt->sub_next = 0;
4287dd7cddfSDavid du Colombier }
4297dd7cddfSDavid du Colombier 
4307dd7cddfSDavid du Colombier /* ------ Save/restore ------ */
4317dd7cddfSDavid du Colombier 
4327dd7cddfSDavid du Colombier /* Clean up the name table before a restore. */
4337dd7cddfSDavid du Colombier /* Currently, this is never called, because the name table is allocated */
4347dd7cddfSDavid du Colombier /* in system VM.  However, for a Level 1 system, we might choose to */
4357dd7cddfSDavid du Colombier /* allocate the name table in global VM; in this case, this routine */
4367dd7cddfSDavid du Colombier /* would be called before doing the global part of a top-level restore. */
4377dd7cddfSDavid du Colombier /* Currently we don't make any attempt to optimize this. */
4387dd7cddfSDavid du Colombier void
names_restore(name_table * nt,alloc_save_t * save)4397dd7cddfSDavid du Colombier names_restore(name_table * nt, alloc_save_t * save)
4407dd7cddfSDavid du Colombier {
4417dd7cddfSDavid du Colombier     /* We simply mark all names older than the save, */
4427dd7cddfSDavid du Colombier     /* and let names_trace_finish sort everything out. */
4437dd7cddfSDavid du Colombier     uint si;
4447dd7cddfSDavid du Colombier 
4457dd7cddfSDavid du Colombier     for (si = 0; si < nt->sub_count; ++si)
4467dd7cddfSDavid du Colombier 	if (nt->sub[si].strings != 0) {
4477dd7cddfSDavid du Colombier 	    uint i;
4487dd7cddfSDavid du Colombier 
4497dd7cddfSDavid du Colombier 	    for (i = 0; i < nt_sub_size; ++i) {
4507dd7cddfSDavid du Colombier 		name_string_t *pnstr =
4517dd7cddfSDavid du Colombier 		    names_index_string_inline(nt, (si << nt_log2_sub_size) + i);
4527dd7cddfSDavid du Colombier 
4537dd7cddfSDavid du Colombier 		if (pnstr->string_bytes == 0)
4547dd7cddfSDavid du Colombier 		    pnstr->mark = 0;
4557dd7cddfSDavid du Colombier 		else if (pnstr->foreign_string) {
4567dd7cddfSDavid du Colombier 		    /* Avoid storing into a read-only name string. */
4577dd7cddfSDavid du Colombier 		    if (!pnstr->mark)
4587dd7cddfSDavid du Colombier 			pnstr->mark = 1;
4597dd7cddfSDavid du Colombier 		} else
4607dd7cddfSDavid du Colombier 		    pnstr->mark =
4617dd7cddfSDavid du Colombier 			!alloc_is_since_save(pnstr->string_bytes, save);
4627dd7cddfSDavid du Colombier 	    }
4637dd7cddfSDavid du Colombier 	}
4647dd7cddfSDavid du Colombier     names_trace_finish(nt, NULL);
4657dd7cddfSDavid du Colombier }
4667dd7cddfSDavid du Colombier 
4677dd7cddfSDavid du Colombier /* ------ Internal procedures ------ */
4687dd7cddfSDavid du Colombier 
4697dd7cddfSDavid du Colombier /* Allocate the next sub-table. */
4707dd7cddfSDavid du Colombier private int
name_alloc_sub(name_table * nt)4717dd7cddfSDavid du Colombier name_alloc_sub(name_table * nt)
4727dd7cddfSDavid du Colombier {
4737dd7cddfSDavid du Colombier     gs_memory_t *mem = nt->memory;
4747dd7cddfSDavid du Colombier     uint sub_index = nt->sub_next;
4757dd7cddfSDavid du Colombier     name_sub_table *sub;
4767dd7cddfSDavid du Colombier     name_string_sub_table_t *ssub;
4777dd7cddfSDavid du Colombier 
4787dd7cddfSDavid du Colombier     for (;; ++sub_index) {
4797dd7cddfSDavid du Colombier 	if (sub_index > nt->max_sub_count)
4807dd7cddfSDavid du Colombier 	    return_error(e_limitcheck);
4817dd7cddfSDavid du Colombier 	if (nt->sub[sub_index].names == 0)
4827dd7cddfSDavid du Colombier 	    break;
4837dd7cddfSDavid du Colombier     }
4847dd7cddfSDavid du Colombier     nt->sub_next = sub_index + 1;
4857dd7cddfSDavid du Colombier     if (nt->sub_next > nt->sub_count)
4867dd7cddfSDavid du Colombier 	nt->sub_count = nt->sub_next;
4877dd7cddfSDavid du Colombier     sub = gs_alloc_struct(mem, name_sub_table, &st_name_sub_table,
4887dd7cddfSDavid du Colombier 			  "name_alloc_sub(sub-table)");
4897dd7cddfSDavid du Colombier     ssub = gs_alloc_struct(mem, name_string_sub_table_t,
4907dd7cddfSDavid du Colombier 			   &st_name_string_sub_table,
4917dd7cddfSDavid du Colombier 			  "name_alloc_sub(string sub-table)");
4927dd7cddfSDavid du Colombier     if (sub == 0 || ssub == 0) {
4937dd7cddfSDavid du Colombier 	gs_free_object(mem, ssub, "name_alloc_sub(string sub-table)");
4947dd7cddfSDavid du Colombier 	gs_free_object(mem, sub, "name_alloc_sub(sub-table)");
4957dd7cddfSDavid du Colombier 	return_error(e_VMerror);
4967dd7cddfSDavid du Colombier     }
4977dd7cddfSDavid du Colombier     memset(sub, 0, sizeof(name_sub_table));
4987dd7cddfSDavid du Colombier     memset(ssub, 0, sizeof(name_string_sub_table_t));
4997dd7cddfSDavid du Colombier     /* The following code is only used if EXTEND_NAMES is non-zero. */
5007dd7cddfSDavid du Colombier #if name_extension_bits > 0
5013ff48bf5SDavid du Colombier     sub->high_index = (sub_index >> (16 - nt_log2_sub_size)) << 16;
5027dd7cddfSDavid du Colombier #endif
5037dd7cddfSDavid du Colombier     nt->sub[sub_index].names = sub;
5047dd7cddfSDavid du Colombier     nt->sub[sub_index].strings = ssub;
5057dd7cddfSDavid du Colombier     /* Add the newly allocated entries to the free list. */
5067dd7cddfSDavid du Colombier     /* Note that the free list will only be properly sorted if */
5077dd7cddfSDavid du Colombier     /* it was empty initially. */
5087dd7cddfSDavid du Colombier     name_scan_sub(nt, sub_index, false);
5097dd7cddfSDavid du Colombier #ifdef DEBUG
5107dd7cddfSDavid du Colombier     if (gs_debug_c('n')) {	/* Print the lengths of the hash chains. */
5117dd7cddfSDavid du Colombier 	int i0;
5127dd7cddfSDavid du Colombier 
5137dd7cddfSDavid du Colombier 	for (i0 = 0; i0 < NT_HASH_SIZE; i0 += 16) {
5147dd7cddfSDavid du Colombier 	    int i;
5157dd7cddfSDavid du Colombier 
5167dd7cddfSDavid du Colombier 	    dlprintf1("[n]chain %d:", i0);
5177dd7cddfSDavid du Colombier 	    for (i = i0; i < i0 + 16; i++) {
5187dd7cddfSDavid du Colombier 		int n = 0;
5197dd7cddfSDavid du Colombier 		uint nidx;
5207dd7cddfSDavid du Colombier 
5217dd7cddfSDavid du Colombier 		for (nidx = nt->hash[i]; nidx != 0;
5227dd7cddfSDavid du Colombier 		     nidx = name_next_index(nidx,
5237dd7cddfSDavid du Colombier 					    names_index_string_inline(nt, nidx))
5247dd7cddfSDavid du Colombier 		    )
5257dd7cddfSDavid du Colombier 		    n++;
5267dd7cddfSDavid du Colombier 		dprintf1(" %d", n);
5277dd7cddfSDavid du Colombier 	    }
5287dd7cddfSDavid du Colombier 	    dputc('\n');
5297dd7cddfSDavid du Colombier 	}
5307dd7cddfSDavid du Colombier     }
5317dd7cddfSDavid du Colombier #endif
5327dd7cddfSDavid du Colombier     return 0;
5337dd7cddfSDavid du Colombier }
5347dd7cddfSDavid du Colombier 
5357dd7cddfSDavid du Colombier /* Free a sub-table. */
5367dd7cddfSDavid du Colombier private void
name_free_sub(name_table * nt,uint sub_index)5377dd7cddfSDavid du Colombier name_free_sub(name_table * nt, uint sub_index)
5387dd7cddfSDavid du Colombier {
5397dd7cddfSDavid du Colombier     gs_free_object(nt->memory, nt->sub[sub_index].strings,
5407dd7cddfSDavid du Colombier 		   "name_free_sub(string sub-table)");
5417dd7cddfSDavid du Colombier     gs_free_object(nt->memory, nt->sub[sub_index].names,
5427dd7cddfSDavid du Colombier 		   "name_free_sub(sub-table)");
5437dd7cddfSDavid du Colombier     nt->sub[sub_index].names = 0;
5447dd7cddfSDavid du Colombier     nt->sub[sub_index].strings = 0;
5457dd7cddfSDavid du Colombier }
5467dd7cddfSDavid du Colombier 
5477dd7cddfSDavid du Colombier /* Scan a sub-table and add unmarked entries to the free list. */
5487dd7cddfSDavid du Colombier /* We add the entries in decreasing count order, so the free list */
5497dd7cddfSDavid du Colombier /* will stay sorted.  If all entries are unmarked and free_empty is true, */
5507dd7cddfSDavid du Colombier /* free the sub-table. */
5517dd7cddfSDavid du Colombier private void
name_scan_sub(name_table * nt,uint sub_index,bool free_empty)5527dd7cddfSDavid du Colombier name_scan_sub(name_table * nt, uint sub_index, bool free_empty)
5537dd7cddfSDavid du Colombier {
5547dd7cddfSDavid du Colombier     name_string_sub_table_t *ssub = nt->sub[sub_index].strings;
5557dd7cddfSDavid du Colombier     uint free = nt->free;
5567dd7cddfSDavid du Colombier     uint nbase = sub_index << nt_log2_sub_size;
5577dd7cddfSDavid du Colombier     uint ncnt = nbase + (nt_sub_size - 1);
5587dd7cddfSDavid du Colombier     bool keep = !free_empty;
5597dd7cddfSDavid du Colombier 
5607dd7cddfSDavid du Colombier     if (ssub == 0)
5617dd7cddfSDavid du Colombier 	return;
5627dd7cddfSDavid du Colombier     if (nbase == 0)
5637dd7cddfSDavid du Colombier 	nbase = 1, keep = true;	/* don't free name 0 */
5647dd7cddfSDavid du Colombier     for (;; --ncnt) {
5657dd7cddfSDavid du Colombier 	uint nidx = name_count_to_index(ncnt);
5667dd7cddfSDavid du Colombier 	name_string_t *pnstr = &ssub->strings[nidx & nt_sub_index_mask];
5677dd7cddfSDavid du Colombier 
5687dd7cddfSDavid du Colombier 	if (pnstr->mark)
5697dd7cddfSDavid du Colombier 	    keep = true;
5707dd7cddfSDavid du Colombier 	else {
5717dd7cddfSDavid du Colombier 	    set_name_next_index(nidx, pnstr, free);
5727dd7cddfSDavid du Colombier 	    free = nidx;
5737dd7cddfSDavid du Colombier 	}
5747dd7cddfSDavid du Colombier 	if (ncnt == nbase)
5757dd7cddfSDavid du Colombier 	    break;
5767dd7cddfSDavid du Colombier     }
5777dd7cddfSDavid du Colombier     if (keep)
5787dd7cddfSDavid du Colombier 	nt->free = free;
5797dd7cddfSDavid du Colombier     else {
5807dd7cddfSDavid du Colombier 	/* No marked entries, free the sub-table. */
5817dd7cddfSDavid du Colombier 	name_free_sub(nt, sub_index);
5827dd7cddfSDavid du Colombier 	if (sub_index == nt->sub_count - 1) {
5837dd7cddfSDavid du Colombier 	    /* Back up over a final run of deleted sub-tables. */
5847dd7cddfSDavid du Colombier 	    do {
5857dd7cddfSDavid du Colombier 		--sub_index;
5867dd7cddfSDavid du Colombier 	    } while (nt->sub[sub_index].names == 0);
5877dd7cddfSDavid du Colombier 	    nt->sub_count = sub_index + 1;
5887dd7cddfSDavid du Colombier 	    if (nt->sub_next > sub_index)
5897dd7cddfSDavid du Colombier 		nt->sub_next = sub_index;
5907dd7cddfSDavid du Colombier 	} else if (nt->sub_next == sub_index)
5917dd7cddfSDavid du Colombier 	    nt->sub_next--;
5927dd7cddfSDavid du Colombier     }
5937dd7cddfSDavid du Colombier }
5947dd7cddfSDavid du Colombier 
5957dd7cddfSDavid du Colombier /* Garbage collector enumeration and relocation procedures. */
5967dd7cddfSDavid du Colombier private
ENUM_PTRS_BEGIN_PROC(name_table_enum_ptrs)5977dd7cddfSDavid du Colombier ENUM_PTRS_BEGIN_PROC(name_table_enum_ptrs)
5987dd7cddfSDavid du Colombier {
5997dd7cddfSDavid du Colombier     EV_CONST name_table *const nt = vptr;
6007dd7cddfSDavid du Colombier     uint i = index >> 1;
6017dd7cddfSDavid du Colombier 
6027dd7cddfSDavid du Colombier     if (i >= nt->sub_count)
6037dd7cddfSDavid du Colombier 	return 0;
6047dd7cddfSDavid du Colombier     if (index & 1)
6057dd7cddfSDavid du Colombier 	ENUM_RETURN(nt->sub[i].strings);
6067dd7cddfSDavid du Colombier     else
6077dd7cddfSDavid du Colombier 	ENUM_RETURN(nt->sub[i].names);
6087dd7cddfSDavid du Colombier }
6097dd7cddfSDavid du Colombier ENUM_PTRS_END_PROC
RELOC_PTRS_WITH(name_table_reloc_ptrs,name_table * nt)6107dd7cddfSDavid du Colombier private RELOC_PTRS_WITH(name_table_reloc_ptrs, name_table *nt)
6117dd7cddfSDavid du Colombier {
6127dd7cddfSDavid du Colombier     uint sub_count = nt->sub_count;
6137dd7cddfSDavid du Colombier     uint i;
6147dd7cddfSDavid du Colombier 
6157dd7cddfSDavid du Colombier     /* Now we can relocate the sub-table pointers. */
6167dd7cddfSDavid du Colombier     for (i = 0; i < sub_count; i++) {
6177dd7cddfSDavid du Colombier 	RELOC_VAR(nt->sub[i].names);
6187dd7cddfSDavid du Colombier 	RELOC_VAR(nt->sub[i].strings);
6197dd7cddfSDavid du Colombier     }
6207dd7cddfSDavid du Colombier     /*
6217dd7cddfSDavid du Colombier      * We also need to relocate the cached value pointers.
6227dd7cddfSDavid du Colombier      * We don't do this here, but in a separate scan over the
6237dd7cddfSDavid du Colombier      * permanent dictionaries, at the very end of garbage collection.
6247dd7cddfSDavid du Colombier      */
6257dd7cddfSDavid du Colombier }
6267dd7cddfSDavid du Colombier RELOC_PTRS_END
6277dd7cddfSDavid du Colombier 
ENUM_PTRS_BEGIN_PROC(name_string_sub_enum_ptrs)6287dd7cddfSDavid du Colombier private ENUM_PTRS_BEGIN_PROC(name_string_sub_enum_ptrs)
6297dd7cddfSDavid du Colombier {
6307dd7cddfSDavid du Colombier     return 0;
6317dd7cddfSDavid du Colombier }
6327dd7cddfSDavid du Colombier ENUM_PTRS_END_PROC
RELOC_PTRS_BEGIN(name_string_sub_reloc_ptrs)6337dd7cddfSDavid du Colombier private RELOC_PTRS_BEGIN(name_string_sub_reloc_ptrs)
6347dd7cddfSDavid du Colombier {
6357dd7cddfSDavid du Colombier     name_string_t *pnstr = ((name_string_sub_table_t *)vptr)->strings;
6367dd7cddfSDavid du Colombier     uint i;
6377dd7cddfSDavid du Colombier 
6387dd7cddfSDavid du Colombier     for (i = 0; i < nt_sub_size; ++pnstr, ++i) {
6397dd7cddfSDavid du Colombier 	if (pnstr->string_bytes != 0 && !pnstr->foreign_string) {
6407dd7cddfSDavid du Colombier 	    gs_const_string nstr;
6417dd7cddfSDavid du Colombier 
6427dd7cddfSDavid du Colombier 	    nstr.data = pnstr->string_bytes;
6437dd7cddfSDavid du Colombier 	    nstr.size = pnstr->string_size;
6447dd7cddfSDavid du Colombier 	    RELOC_CONST_STRING_VAR(nstr);
6457dd7cddfSDavid du Colombier 	    pnstr->string_bytes = nstr.data;
6467dd7cddfSDavid du Colombier 	}
6477dd7cddfSDavid du Colombier     }
6487dd7cddfSDavid du Colombier }
6497dd7cddfSDavid du Colombier RELOC_PTRS_END
650