aboutsummaryrefslogtreecommitdiff
path: root/gcc/gtype.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/gtype.c')
-rw-r--r--gcc/gtype.c1922
1 files changed, 1922 insertions, 0 deletions
diff --git a/gcc/gtype.c b/gcc/gtype.c
new file mode 100644
index 00000000000..f5018a271f9
--- /dev/null
+++ b/gcc/gtype.c
@@ -0,0 +1,1922 @@
+/* Generic data handling for GNU CC.
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "intl.h"
+#include "tree.h"
+#include "rtl.h"
+#include "function.h"
+#include "expr.h"
+#include "c-tree.h"
+#include "toplev.h"
+#include "hashtab.h"
+#include "md5.h"
+#include "defaults.h"
+#include "hash.h"
+#include "ggc.h"
+#include "tm_p.h"
+
+/* Definitions of all the types we know. */
+typedef struct pch_writer_context
+{
+ htab_t pointer_h;
+ unsigned n_constant[num_type_defs];
+ unsigned n[num_type_defs];
+ const void **ptrs[num_type_defs];
+ unsigned max_size[num_type_defs];
+ FILE *f;
+ int *listd; /* Record what objects the listed variables point to. */
+ size_t listd_ndx;
+ size_t string_size;
+ char *string_table;
+} *wctx_t;
+
+struct pointer_ent
+{
+ const void *v;
+ unsigned ndx;
+ type_definition_p td;
+};
+
+static size_t constant_size_fetcher
+PARAMS ((const void *, type_definition_p));
+
+static code_type tree_code_fetcher PARAMS ((const void *));
+static size_t tree_size_fetcher PARAMS ((const void *, type_definition_p ));
+static int tree_more_fields PARAMS ((struct field_definition_s * ,
+ const void *,
+ unsigned , code_type ,
+ type_definition_p ));
+
+static size_t rtx_size_fetcher PARAMS ((const void *, type_definition_p ));
+static int rtx_more_fields PARAMS ((struct field_definition_s * ,
+ const void *,
+ unsigned, code_type ,
+ type_definition_p ));
+
+static size_t rtvec_size_fetcher PARAMS ((const void *,
+ type_definition_p ));
+static int rtvec_more_fields PARAMS ((struct field_definition_s * ,
+ const void *,
+ unsigned , code_type ,
+ type_definition_p ));
+
+static size_t string_size_fetcher PARAMS ((const void *,
+ type_definition_p ));
+
+static size_t regno_reg_rtx_size_fetcher PARAMS ((const void *,
+ type_definition_p ));
+static int regno_reg_rtx_more_fields PARAMS ((struct field_definition_s * ,
+ const void *,
+ unsigned , code_type ,
+ type_definition_p ));
+static size_t regno_pointer_flag_size_fetcher PARAMS (( const void *, type_definition_p ));
+
+static size_t varray_size_fetcher PARAMS ((const void *,
+ type_definition_p ));
+static int varray_more_fields PARAMS ((struct field_definition_s * ,
+ const void *,
+ unsigned , code_type ,
+ type_definition_p ));
+
+static int typed_addresses_list_more_fields PARAMS ((struct field_definition_s * ,
+ const void *, unsigned , code_type , type_definition_p ));
+static void setup_strtab PARAMS ((wctx_t));
+static void record_listed_nodes PARAMS ((void **v_p, type_definition_p,
+ void *));
+static size_t htab_size_fetcher PARAMS (( const void *, type_definition_p ));
+static int htab_more_fields PARAMS (( struct field_definition_s *, const void *,
+ unsigned ,
+ code_type,
+ type_definition_p));
+
+extern void add_hash_tree_addresses PARAMS ((typed_addresses_list_p list,
+ struct htab *p , size_t, const char *));
+
+/* Size fetcher for structures with constant size; just returns SIZE from
+ the type definition. */
+
+static size_t
+constant_size_fetcher (v, td)
+ const void *v ATTRIBUTE_UNUSED;
+ type_definition_p td;
+{
+ return td->size;
+}
+
+static code_type
+tree_code_fetcher (t_v)
+ const void *t_v;
+{
+ tree t = (tree) t_v;
+ return TREE_CODE (t) << 8 | TREE_CODE_CLASS (TREE_CODE (t));
+}
+
+static size_t
+tree_size_fetcher (v, td)
+ const void *v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ return tree_size ((tree) v);
+}
+
+static int
+tree_more_fields (fp, t_v, n, c, td)
+ struct field_definition_s *fp;
+ const void *t_v;
+ unsigned n;
+ code_type c;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ const tree t = (tree) t_v;
+ enum tree_code tc = (c >> 8) & 0xFF;
+
+ if (tc == TREE_VEC && (long) n < TREE_VEC_LENGTH (t))
+ {
+ fp->offset = (offsetof (union tree_node, vec.a)
+ + n * sizeof (TREE_VEC_ELT (t, 0)));
+ fp->type = tree_type_def;
+ return 1;
+ }
+ else if (((c & 0xFF) == 'r' || (c & 0xFF) == '<'
+ || (c & 0xFF) == '1' || (c & 0xFF) == '2'
+ || (c & 0xFF) == 'e' || (c & 0xFF) == 's')
+ && (long) n < TREE_CODE_LENGTH (tc))
+ {
+ fp->offset = (offsetof (union tree_node, exp.operands)
+ + n * sizeof (TREE_OPERAND (t, 0)));
+ fp->type =
+ ((long) n >= first_rtl_op (tc) ? rtx_type_def : tree_type_def);
+ return 1;
+ }
+
+ return 0;
+}
+
+static struct field_definition_s tree_field_defs[] = {
+ {0, 0, offsetof (union tree_node, common.chain), tree_type_def},
+ {0, 0, offsetof (union tree_node, common.type), tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.filename), string_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.size), tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.size_unit), tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.name), tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.context), tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.arguments), tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.result), tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.initial), tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.abstract_origin),
+ tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.assembler_name),
+ tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.section_name), tree_type_def},
+#if 0
+ {'d', 0xFF, offsetof (union tree_node, decl.machine_attributes), tree_type_def},
+#endif
+ {'d', 0xFF, offsetof (union tree_node, decl.rtl), rtx_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.live_range_rtl), rtx_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.vindex), tree_type_def},
+ {FUNCTION_DECL << 8, 0xFF00,
+ offsetof (union tree_node, decl.u2.f), function_type_def},
+ {PARM_DECL << 8, 0xFF00,
+ offsetof (union tree_node, decl.u2.r), rtx_type_def},
+ {FIELD_DECL << 8, 0xFF00,
+ offsetof (union tree_node, decl.u2.t), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.values), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.size), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.size_unit), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.attributes), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.pointer_to), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.reference_to), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.name), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.minval), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.maxval), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.next_variant), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.main_variant), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.binfo), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.context), tree_type_def},
+ {'b', 0xFF, offsetof (union tree_node, block.vars), tree_type_def},
+ {'b', 0xFF, offsetof (union tree_node, block.subblocks), tree_type_def},
+ {'b', 0xFF, offsetof (union tree_node, block.supercontext), tree_type_def},
+ {'b', 0xFF, offsetof (union tree_node, block.abstract_origin),
+ tree_type_def},
+ {'b', 0xFF, offsetof (union tree_node, block.fragment_origin), tree_type_def},
+ {'b', 0xFF, offsetof (union tree_node, block.fragment_chain), tree_type_def},
+
+ {'c', 0xFF, offsetof (union tree_node, real_cst.rtl), rtx_type_def},
+ {COMPLEX_CST << 8, 0xFF00,
+ offsetof (union tree_node, complex.real), tree_type_def},
+ {COMPLEX_CST << 8, 0xFF00,
+ offsetof (union tree_node, complex.imag), tree_type_def},
+ {STRING_CST << 8, 0xFF00,
+ offsetof (union tree_node, string.pointer), string_type_def},
+ {IDENTIFIER_NODE << 8, 0xFF00,
+ offsetof (union tree_node, identifier.id.str), string_type_def},
+ {TREE_LIST << 8, 0xFF00,
+ offsetof (union tree_node, list.purpose), tree_type_def},
+ {TREE_LIST << 8, 0xFF00,
+ offsetof (union tree_node, list.value), tree_type_def},
+ /* TREE_VEC_ELT is dealt with by MORE_FIELDS. */
+ /* expressions are dealt with by MORE_FIELDS. */
+
+ /* The remaining unused entries are available to hold such things as
+ decl.lang_specific, type.lang_specific, and any extra fields
+ introduced by a 'struct lang_identifier'. Normally, you'd simply
+ say
+
+ { 'd', 0xFF, offsetof (union tree_node, decl.lang_specific),
+ lang_decl_type_def },
+ { 't', 0xFF, offsetof (union tree_node, type.lang_specific),
+ lang_type_type_def },
+
+ for the first two, but some frontends put bizzare things in these fields.
+ */
+ NO_MORE_FIELDS, NO_MORE_FIELDS, NO_MORE_FIELDS, NO_MORE_FIELDS,
+ NO_MORE_FIELDS, NO_MORE_FIELDS, NO_MORE_FIELDS, NO_MORE_FIELDS,
+ NO_MORE_FIELDS, NO_MORE_FIELDS, NO_MORE_FIELDS, NO_MORE_FIELDS,
+ NO_MORE_FIELDS
+};
+
+
+/* This is how languages handle adding their favourite stuff
+at the end of a tree... */
+
+void
+add_tree_fields (fields)
+ const struct field_definition_s *fields;
+{
+ unsigned i;
+ enum
+ {
+ num_tree_fields = sizeof (tree_field_defs) / sizeof (tree_field_defs[0])
+ };
+
+ i = 0;
+ while (tree_field_defs[i].type != NULL)
+ i++;
+ for (; i < num_tree_fields; i++)
+ if (fields->type != NULL)
+ tree_field_defs[i] = *fields++;
+ else
+ return;
+ abort (); /* Need to add more NO_MORE_FIELDS to tree_field_defs. */
+}
+
+static size_t
+rtx_size_fetcher (r_v, td)
+ const void *r_v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ return (sizeof (struct rtx_def) +
+ (GET_RTX_LENGTH (GET_CODE ((rtx) r_v)) - 1) * sizeof (rtunion));
+}
+
+static int
+rtx_more_fields (fp, r_v, n, c, td)
+ struct field_definition_s *fp;
+ const void *r_v;
+ unsigned n;
+ code_type c ATTRIBUTE_UNUSED;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ const rtx r = (rtx) r_v;
+ char fc = GET_RTX_FORMAT (GET_CODE (r))[n];
+
+ fp->offset = (offsetof (struct rtx_def, fld) + n * sizeof (rtunion));
+ switch (fc)
+ {
+ case '\0':
+ return 0;
+
+ case 'e':
+ case 'u':
+ fp->type = rtx_type_def;
+ break;
+ case 'V':
+ case 'E':
+ fp->type = rtvec_type_def;
+ break;
+ case 'S':
+ case 's':
+ case 'T':
+ fp->type = string_type_def;
+ break;
+ case 't':
+ fp->type = tree_type_def;
+ break;
+ case '0':
+ switch (GET_CODE (r))
+ {
+ case JUMP_INSN:
+ case LABEL_REF:
+ case CONST_DOUBLE:
+ fp->type = rtx_type_def;
+ break;
+ case CODE_LABEL:
+ if (n == 3)
+ fp->type = NULL;
+ else
+ fp->type = rtx_type_def;
+ break;
+ case MEM:
+ case REG:
+ case SCRATCH:
+ case ADDR_DIFF_VEC:
+ fp->type = NULL;
+ break;
+
+ case NOTE:
+ switch (NOTE_LINE_NUMBER (r))
+ {
+ case NOTE_INSN_RANGE_BEG:
+ case NOTE_INSN_RANGE_END:
+ case NOTE_INSN_LIVE:
+ case NOTE_INSN_EXPECTED_VALUE:
+ fp->type = rtx_type_def;
+ break;
+ case NOTE_INSN_BLOCK_BEG:
+ case NOTE_INSN_BLOCK_END:
+ fp->type = tree_type_def;
+ break;
+ case NOTE_INSN_DELETED_LABEL:
+ fp->type = string_type_def;
+ break;
+ default:
+ if (NOTE_LINE_NUMBER (r) >= 0)
+ fp->type = string_type_def;
+ else
+ fp->type = NULL;
+ break;
+ }
+ break;
+ default:
+ abort ();
+ }
+ break;
+ default:
+ fp->type = NULL;
+ break;
+ }
+ return 1;
+}
+
+static size_t
+rtvec_size_fetcher (v_v, td)
+ const void *v_v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ return (sizeof (struct rtvec_def) +
+ (GET_NUM_ELEM ((rtvec) v_v) - 1) * sizeof (rtx));
+}
+
+static int
+rtvec_more_fields (fp, v_v, n, c, td)
+ struct field_definition_s *fp;
+ const void *v_v;
+ unsigned n;
+ code_type c ATTRIBUTE_UNUSED;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ if ((long) n < GET_NUM_ELEM ((rtvec) v_v))
+ {
+ fp->offset = (offsetof (struct rtvec_def, elem) + n * sizeof (rtx));
+ fp->type = rtx_type_def;
+ return 1;
+ }
+ return 0;
+}
+
+static size_t
+string_size_fetcher (v_v, td)
+ const void *v_v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ return strlen ((char *) v_v) + 1;
+}
+
+
+static const struct field_definition_s function_field_defs[] = {
+#if 1
+ {0, 0, offsetof (struct function, next_global), function_type_def},
+ {0, 0, offsetof (struct function, next), function_type_def},
+#endif
+ /* struct eh_status *eh;
+ struct stmt_status *stmt;
+ struct expr_status *expr; */
+ {0, 0, offsetof (struct function, emit), emit_status_type_def},
+ /* struct varasm_status *varasm; */
+ {0, 0, offsetof (struct function, name), string_type_def},
+ {0, 0, offsetof (struct function, decl), tree_type_def},
+#if 0
+ {0, 0, offsetof (struct function, outer), function_type_def},
+#endif
+ {0, 0, offsetof (struct function, arg_offset_rtx), rtx_type_def},
+ /* CUMULATIVE_ARGS args_info; */
+ {0, 0, offsetof (struct function, return_rtx), rtx_type_def},
+ {0, 0, offsetof (struct function, cannot_inline), string_type_def},
+ {0, 0, offsetof (struct function, x_nonlocal_labels), tree_type_def},
+ {0, 0, offsetof (struct function, x_nonlocal_goto_handler_slots),
+ rtx_type_def},
+ {0, 0, offsetof (struct function, x_nonlocal_goto_handler_labels),
+ rtx_type_def},
+ {0, 0, offsetof (struct function, x_nonlocal_goto_stack_level),
+ rtx_type_def},
+ {0, 0, offsetof (struct function, x_cleanup_label), rtx_type_def},
+ {0, 0, offsetof (struct function, x_return_label), rtx_type_def},
+ {0, 0, offsetof (struct function, x_save_expr_regs), rtx_type_def},
+ {0, 0, offsetof (struct function, x_stack_slot_list), rtx_type_def},
+ {0, 0, offsetof (struct function, x_rtl_expr_chain), tree_type_def},
+ {0, 0, offsetof (struct function, x_tail_recursion_label), rtx_type_def},
+ {0, 0, offsetof (struct function, x_arg_pointer_save_area), rtx_type_def},
+ {0, 0, offsetof (struct function, x_clobber_return_insn), rtx_type_def},
+ {0, 0, offsetof (struct function, x_context_display), tree_type_def},
+ {0, 0, offsetof (struct function, x_trampoline_list), tree_type_def},
+ {0, 0, offsetof (struct function, x_parm_birth_insn), rtx_type_def},
+ {0, 0, offsetof (struct function, x_last_parm_insn), rtx_type_def},
+ /* rtx *x_parm_reg_stack_loc; */
+ /* struct temp_slot *x_temp_slots; */
+ /* struct var_refs_queue *fixup_var_refs_queue; */
+ {0, 0, offsetof (struct function, original_arg_vector), rtvec_type_def},
+ {0, 0, offsetof (struct function, original_decl_initial), tree_type_def},
+ {0, 0, offsetof (struct function, inl_last_parm_insn), rtx_type_def},
+ /* struct machine_function *machine */
+ {0, 0, offsetof (struct function, language), lang_function_type_def},
+ {0, 0, offsetof (struct function, epilogue_delay_list), rtx_type_def},
+ NO_MORE_FIELDS
+};
+
+static size_t
+regno_pointer_flag_size_fetcher (v, td)
+ const void *v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ return ((struct emit_status *)v)->regno_pointer_align_length;
+}
+
+static size_t
+regno_reg_rtx_size_fetcher (v, td)
+ const void *v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ return ((struct emit_status *) v)->regno_pointer_align_length * sizeof (rtx);
+}
+
+static int
+regno_reg_rtx_more_fields (fp, v, n, c, td)
+ struct field_definition_s *fp;
+ const void *v;
+ unsigned n;
+ code_type c ATTRIBUTE_UNUSED;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ struct emit_status *e = (struct emit_status *) v;
+
+ if (n < (unsigned) e->regno_pointer_align_length)
+ {
+ fp->offset = n * sizeof (rtx);
+ fp->type = rtx_type_def;
+ return 1;
+ }
+ return 0;
+}
+
+static const struct field_definition_s emit_status_field_defs[] = {
+ {0, 0, offsetof (struct emit_status, x_first_insn), rtx_type_def},
+ {0, 0, offsetof (struct emit_status, x_last_insn), rtx_type_def},
+ /* tree sequence_rtl_expr; -- only valid while generating a sequence. */
+ /* struct sequence_stack *sequence_stack; -- should be NULL. */
+ /* char *x_last_filename; -- only used to emit NOTEs. */
+ NO_MORE_FIELDS
+};
+
+static const struct subobject_definition_s emit_status_subobject_defs[] = {
+ { 0, 0, offsetof (struct emit_status, regno_pointer_align),
+ regno_pointer_flag_size_fetcher, NULL },
+ { 0, 0, offsetof (struct emit_status, x_regno_reg_rtx),
+ regno_reg_rtx_size_fetcher, regno_reg_rtx_more_fields },
+ NO_MORE_SUBOBJECTS
+};
+
+#define VARRAY_HEAD_SIZE \
+ (sizeof (struct varray_head_tag) - sizeof (varray_data))
+
+static size_t
+varray_size_fetcher (v, td)
+ const void *v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ varray_type va = (varray_type) v;
+
+ return va->num_elements * va->element_size + VARRAY_HEAD_SIZE;
+}
+
+static int
+varray_more_fields (fp, v, n, c, td)
+ struct field_definition_s *fp;
+ const void *v;
+ unsigned n;
+ code_type c ATTRIBUTE_UNUSED;
+ type_definition_p td;
+{
+ varray_type va = (varray_type) v;
+
+ if (n < VARRAY_SIZE (va))
+ {
+ int i = type_to_type_index (td) + (tree_type_ndx - varray_tree_type_ndx);
+
+ fp->offset =
+ (offsetof (struct varray_head_tag, data) + n * va->element_size);
+ fp->type = type_index_to_type (i);
+ return 1;
+ }
+ return 0;
+}
+
+#define HTAB_HEAD_SIZE \
+ (sizeof ( htab_t))
+
+static size_t
+htab_size_fetcher (v, td)
+ const void *v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ struct htab *va = (struct htab *) v;
+
+ return va->size + HTAB_HEAD_SIZE;
+}
+
+static int
+htab_more_fields (fp, v, n, c, td)
+ struct field_definition_s *fp;
+ const void *v;
+ unsigned n;
+ code_type c ATTRIBUTE_UNUSED;
+ type_definition_p td;
+{
+ struct htab *va = (struct htab *) v;
+
+#if 0
+ if (n < VARRAY_SIZE (va))
+ {
+ int i = type_to_type_index (td) + (tree_type_ndx - htab_tree_type_ndx);
+
+ fp->offset =
+ (offsetof (struct htab_head_tag, data) + n * va->element_size);
+ fp->type = type_index_to_type (i);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+static int
+typed_addresses_list_more_fields (fp, v, n, c, td)
+ struct field_definition_s *fp;
+ const void *v;
+ unsigned n;
+ code_type c ATTRIBUTE_UNUSED;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ typed_addresses_list_p l = (typed_addresses_list_p) v;
+
+ if (n < TYPED_ADDRESSES_LIST_CHUNK_SIZE)
+ {
+ fp->offset = (offsetof (typed_addresses_list, ta)
+ + n * sizeof (struct typed_addresses_s)
+ + offsetof (struct typed_addresses_s, p));
+ fp->type = l->ta[n].td;
+ return 1;
+ }
+ else if (n == TYPED_ADDRESSES_LIST_CHUNK_SIZE)
+ {
+ fp->offset = offsetof (typed_addresses_list, next);
+ fp->type = typed_addresses_list_type_def;
+ return 1;
+ }
+ return 0;
+}
+
+/* A description of the pointer fields in a type. */
+
+struct type_definition_s basic_type_defs[num_type_defs] = {
+ { /* tree */
+ tree_code_fetcher,
+ tree_size_fetcher,
+ NULL,
+ sizeof (struct tree_common),
+ tree_field_defs,
+ tree_more_fields,
+ NULL,
+ 1},
+ { /* rtx */
+ NULL,
+ rtx_size_fetcher,
+ NULL,
+ sizeof (struct rtx_def) - sizeof (rtunion),
+ NULL,
+ rtx_more_fields,
+ NULL,
+ 1}
+ ,
+ { /* rtvec */
+ NULL,
+ rtvec_size_fetcher,
+ NULL,
+ sizeof (struct rtvec_def) - sizeof (rtx),
+ NULL,
+ rtvec_more_fields,
+ NULL,
+ 1}
+ ,
+ { /* string */
+ NULL, string_size_fetcher, NULL, 0, NULL, NULL, NULL, 1}
+ ,
+ /* struct lang_type, initialized by the language-specific frontends. */
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 1}
+ ,
+ /* struct lang_decl, initialized by the language-specific frontends. */
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 1}
+ ,
+ { /* struct function */
+ NULL,
+ constant_size_fetcher,
+ NULL,
+ sizeof (struct function),
+ function_field_defs,
+ NULL,
+ NULL,
+ 0},
+ /* struct lang_function, initialized by the language-specific frontends. */
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 1},
+ { /* struct emit_status */
+ NULL,
+ constant_size_fetcher,
+ NULL,
+ sizeof (struct emit_status),
+ emit_status_field_defs,
+ NULL,
+ emit_status_subobject_defs,
+ 0},
+ /* The variable `typevec' in dbxout.c, initialized there. */
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 0},
+ /* struct dbx_file in dbxout.c, initialized there. */
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 0},
+ /* The various varray types, arranged in the same order as
+ tree/rtx/rtvec/string above. They are distinguished by their
+ addresses. */
+ {NULL, htab_size_fetcher, NULL, HTAB_HEAD_SIZE, NULL,
+ htab_more_fields, NULL, -1},
+ {NULL, varray_size_fetcher, NULL, VARRAY_HEAD_SIZE, NULL,
+ varray_more_fields, NULL, -1},
+ {NULL, varray_size_fetcher, NULL, VARRAY_HEAD_SIZE, NULL,
+ varray_more_fields, NULL, -1},
+ {NULL, varray_size_fetcher, NULL, VARRAY_HEAD_SIZE, NULL,
+ varray_more_fields, NULL, -1},
+ {NULL, varray_size_fetcher, NULL, VARRAY_HEAD_SIZE, NULL,
+ varray_more_fields, NULL, -1},
+ { /* typed_addresses_list */
+ NULL,
+ constant_size_fetcher,
+ NULL,
+ sizeof (typed_addresses_list),
+ NULL,
+ typed_addresses_list_more_fields,
+ NULL,
+ 0}
+ ,
+ /* Language-specific types, initialized in the frontend. */
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, -1}
+ ,
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 0}
+ ,
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 0}
+ ,
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 0}
+ ,
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 0}
+ ,
+};
+
+void
+apply_pointer (p, td, pfn, param)
+ void *p;
+ type_definition_p td;
+ pointerfn_fnp pfn;
+ void *param;
+{
+ code_type c = 0;
+
+ if (td->code_fetcher)
+ c = td->code_fetcher (p);
+
+ if (td->field_definitions != NULL)
+ {
+ int i;
+
+ for (i = 0; td->field_definitions[i].type != NULL; i++)
+ if ((c & td->field_definitions[i].mask)
+ == td->field_definitions[i].cond)
+ pfn ((void **) ((char *) p + td->field_definitions[i].offset),
+ td->field_definitions[i].type, param);
+ }
+ if (td->more_fields)
+ {
+ unsigned i = 0;
+ struct field_definition_s fp;
+
+ fp.cond = fp.mask = 0;
+ while (td->more_fields (&fp, p, i++, c, td))
+ if (fp.type != NULL)
+ pfn ((void **) ((char *) p + fp.offset), fp.type, param);
+ }
+ if (td->subobject_definitions)
+ {
+ subobject_definition_p sd;
+
+ for (sd = td->subobject_definitions; sd->size_fetcher != NULL; sd++)
+ if (sd->fields && ((c & sd->mask) == sd->cond))
+ {
+ unsigned j = 0;
+ struct field_definition_s fp;
+ char *sdf = (char *) *(void **) ((char *) p + sd->offset);
+
+ if (sdf)
+ while (sd->fields (&fp, p, j++, c, td))
+ if (fp.type != NULL)
+ pfn ((void **) (sdf + fp.offset), fp.type, param);
+ }
+ }
+}
+
+
+/* Apply FN with context CTX to every pointer reachable from V, and
+apply SF to every subobject. V has type TD. SF may be NULL in which
+case it is treated as returning 1 if and only if the pointer to the subobject
+is not NULL. */
+
+void
+apply_pointer_recursively (p_p, td_p, pfn, sfn, param)
+ void *p_p;
+ type_definition_p td_p;
+ r_pointerfn_fnp pfn;
+ s_pointerfn_fnp sfn;
+ void *param;
+{
+ enum { worklist_size = 384 };
+ typed_address worklist[worklist_size];
+ unsigned worklist_next;
+
+ worklist[0].p = p_p;
+ worklist[0].td = td_p;
+ worklist_next = 1;
+
+ do
+ {
+ code_type c = 0;
+ type_definition_p td;
+ void *p;
+
+ worklist_next--;
+ p = worklist[worklist_next].p;
+ td = worklist[worklist_next].td;
+
+ if (td->code_fetcher)
+ c = td->code_fetcher (p);
+
+ if (td->field_definitions != NULL)
+ {
+ int i;
+
+ for (i = 0; td->field_definitions[i].type != NULL; i++)
+ if ((c & td->field_definitions[i].mask)
+ == td->field_definitions[i].cond)
+ {
+ void **np = (void **) ((char *) p
+ + td->field_definitions[i].offset);
+ type_definition_p ntd = td->field_definitions[i].type;
+
+ if (pfn (np, ntd, param))
+ {
+ if (worklist_next < worklist_size)
+ {
+ worklist[worklist_next].p = *np;
+ worklist[worklist_next].td = ntd;
+ worklist_next++;
+ }
+ else
+ apply_pointer_recursively (*np, ntd, pfn, sfn, param);
+ }
+ }
+ }
+ if (td->more_fields)
+ {
+ unsigned i = 0;
+ struct field_definition_s fp;
+
+ fp.cond = fp.mask = 0;
+ while (td->more_fields (&fp, p, i++, c, td))
+ if (fp.type != NULL)
+ if (pfn ((void **) ((char *) p + fp.offset), fp.type, param))
+ {
+ void *np = *(void **) ((char *) p + fp.offset);
+
+ if (worklist_next < worklist_size)
+ {
+ worklist[worklist_next].p = np;
+ worklist[worklist_next].td = fp.type;
+ worklist_next++;
+ }
+ else
+ apply_pointer_recursively (np, fp.type, pfn, sfn, param);
+ }
+ }
+ if (td->subobject_definitions)
+ {
+ subobject_definition_p sd;
+
+ for (sd = td->subobject_definitions; sd->size_fetcher != NULL; sd++)
+ if (sd->fields && ((c & sd->mask) == sd->cond))
+ {
+ unsigned j = 0;
+ struct field_definition_s fp;
+
+ char *sdf = (char *) *(void **) ((char *) p + sd->offset);
+
+ if ((!sfn && sdf)
+ || (sfn
+ && sfn (p, td, (void **) ((char *) p + sd->offset),
+ sd, param)))
+ while (sd->fields (&fp, p, j++, c, td))
+ if (fp.type != NULL)
+ if (pfn ((void **) (sdf + fp.offset), fp.type, param))
+ {
+ void *np = *(void **) (sdf + fp.offset);
+
+ if (worklist_next < worklist_size)
+ {
+ worklist[worklist_next].p = np;
+ worklist[worklist_next].td = fp.type;
+ worklist_next++;
+ }
+ else {
+if (fp.offset == 36900 ) haltit();
+ apply_pointer_recursively (np, fp.type, pfn, sfn,
+ param);
+ }
+ }
+ }
+ }
+ }
+ while (worklist_next > 0);
+}
+
+/* Add a block of typed addresses to a list. */
+
+
+void
+add_typed_addresses (list, p, td, count, name)
+ typed_addresses_list_p list;
+ void **p;
+ type_definition_p td;
+ size_t count;
+ const char *name;
+{
+ int i;
+
+#ifdef GT_DEBUG
+ fprintf(stderr,"add_typed_addresses (%s)\n",name);
+#endif
+ while (list->next)
+ list = list->next;
+ if (list->ta[TYPED_ADDRESSES_LIST_CHUNK_SIZE - 1].p)
+ list = list->next = xcalloc (1, sizeof (*list->next));
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++)
+ if (!list->ta[i].p)
+ {
+ list->ta[i].p = p;
+ list->ta[i].td = td;
+ list->ta[i].count = count;
+ list->ta[i].name = name;
+ return;
+ }
+ abort ();
+}
+
+/* Add addresses of various types to a list. */
+
+void
+add_tree_addresses (list, p, count, name)
+ typed_addresses_list_p list;
+ tree *p;
+ size_t count;
+ const char *name;
+{
+#ifdef GT_DEBUG
+ fprintf(stderr,"add_tree_addresses (%s)\n",name);
+#endif
+ add_typed_addresses (list, (void **) p, tree_type_def, count, name);
+}
+
+void
+add_rtx_addresses (list, p, count, name)
+ typed_addresses_list_p list;
+ rtx *p;
+ size_t count;
+ const char *name;
+{
+#ifdef GT_DEBUG
+ fprintf(stderr,"add_rtx_addresses (%s)\n",name);
+#endif
+ add_typed_addresses (list, (void **) p, rtx_type_def, count, name);
+}
+
+void
+add_hash_tree_addresses (list, p, count, name)
+ typed_addresses_list_p list;
+ struct htab *p;
+ size_t count;
+ const char *name;
+{
+#ifdef GT_DEBUG
+ fprintf(stderr,"add_hash_tree_addresses (%s)\n",name);
+#endif
+ add_typed_addresses (list, (void **) p, hash_tree_type_def, count, name);
+}
+
+void
+add_varray_tree_addresses (list, p, count, name)
+ typed_addresses_list_p list;
+ varray_type *p;
+ size_t count;
+ const char *name;
+{
+#ifdef GT_DEBUG
+ fprintf(stderr,"add_varray_tree_addresses (%s)\n",name);
+#endif
+ add_typed_addresses (list, (void **) p, varray_tree_type_def, count, name);
+}
+
+
+/* Do something to each pointer in a list. */
+
+void
+apply_list_pointers (list, fn, ctx)
+ typed_addresses_list_p list;
+ pointerfn_fnp fn;
+ void *ctx;
+{
+ int i;
+ size_t j;
+
+ for (; list; list = list->next)
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++)
+ if (list->ta[i].p && list->ta[i].td)
+ for (j = list->ta[i].count; j > 0; j--)
+ fn (list->ta[i].p + (j - 1), list->ta[i].td, ctx);
+}
+
+/* Do something to each pointer referenced by a list. */
+
+void
+apply_list_pointers_recursively (list, fn, sfn, ctx)
+ typed_addresses_list_p list;
+ r_pointerfn_fnp fn;
+ s_pointerfn_fnp sfn;
+ void *ctx;
+{
+ int i;
+ size_t j;
+
+ for (; list; list = list->next)
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++) {
+#ifdef GT_DEBUG
+ fprintf(stderr,"APLPR(%s)\n",list->ta[i].name);
+#endif
+ if (list->ta[i].p && list->ta[i].td)
+ for (j = list->ta[i].count; j > 0; j--)
+ if (fn (list->ta[i].p + (j - 1), list->ta[i].td, ctx))
+ apply_pointer_recursively (list->ta[i].p[j - 1], list->ta[i].td,
+ fn, sfn, ctx);
+ }
+}
+
+
+/* Add a block of untyped memory to a list. */
+
+void
+add_untyped_address (list, p, size, name)
+ typed_addresses_list_p list;
+ void *p;
+ size_t size;
+ const char *name;
+{
+ int i;
+
+#ifdef GT_DEBUG
+ fprintf(stderr,"add_untyped_address (%s)\n",name);
+#endif
+ while (list->next)
+ list = list->next;
+ if (list->ta[TYPED_ADDRESSES_LIST_CHUNK_SIZE - 1].p)
+ list = list->next = xcalloc (1, sizeof (*list->next));
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++)
+ if (!list->ta[i].p)
+ {
+ list->ta[i].p = (void **) p;
+ list->ta[i].td = NULL;
+ list->ta[i].count = size;
+ list->ta[i].name = name;
+ return;
+ }
+ abort ();
+}
+
+
+/* Do something to each untyped memory block in a list. */
+
+void
+apply_list_untyped (list, fn, ctx)
+ typed_addresses_list_p list;
+ untypedfn_fnp fn;
+ void *ctx;
+{
+ int i;
+
+ for (; list; list = list->next)
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++)
+ if (list->ta[i].p && !list->ta[i].td)
+ fn ((void *) list->ta[i].p, list->ta[i].count, ctx);
+}
+
+/* Remove an address (typed or untyped) from a list. */
+
+void
+remove_list_address (list, p)
+ typed_addresses_list_p list;
+ void *p;
+{
+ int i;
+ for (; list; list = list->next)
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++)
+ if (list->ta[i].p == p)
+ {
+ typed_addresses_list_p tail = list;
+ int taili;
+
+ while (tail->next)
+ tail = tail->next;
+ for (taili = 0; taili < TYPED_ADDRESSES_LIST_CHUNK_SIZE; taili++)
+ if (!tail->ta[taili].p)
+ break;
+
+ list->ta[i] = tail->ta[i];
+ tail->ta[i].p = NULL;
+ return;
+ }
+ abort ();
+}
+
+/* Count items in a list. */
+
+void
+count_list_pointers (list, typed_p, untyped_p)
+ typed_addresses_list_p list;
+ size_t *typed_p;
+ size_t *untyped_p;
+{
+ size_t typed, untyped;
+ int i;
+
+ typed = untyped = 0;
+ for (; list; list = list->next)
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++)
+ if (list->ta[i].p)
+ {
+ if (list->ta[i].td)
+ typed += list->ta[i].count;
+ else
+ untyped++;
+ }
+
+ if (typed_p)
+ *typed_p = typed;
+ if (untyped_p)
+ *untyped_p = untyped;
+}
+
+
+/* Update a checksum of the addresses in LIST. If LIST refers to the
+same list of pointers, the checksum shouldn't vary even between
+different runs of the program. Initially, set CHKSUM to contain
+all zeros. */
+
+void
+sum_type_addresses_list (cksum, list)
+ unsigned char cksum[CHECKSUM_SIZE];
+ typed_addresses_list_p list;
+{
+ struct md5_ctx ctx;
+ unsigned char result[16];
+ typed_addresses_list_p l;
+ int i;
+
+ md5_init_ctx (&ctx);
+ md5_process_bytes (cksum, CHECKSUM_SIZE, &ctx);
+
+ for (l = list; l; l = l->next)
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++)
+ if (l->ta[i].p && !l->ta[i].td)
+ {
+ md5_process_bytes (&l->ta[i].count, sizeof (l->ta[i].count), &ctx);
+ md5_process_bytes (l->ta[i].p, l->ta[i].count, &ctx);
+ }
+
+ for (l = list; l; l = l->next)
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++)
+ if (l->ta[i].p && l->ta[i].td)
+ {
+ int ndx;
+ type_definition_p td = l->ta[i].td;
+ size_t j;
+
+ md5_process_bytes (&l->ta[i].count, sizeof (l->ta[i].count), &ctx);
+ ndx = type_to_type_index (td);
+ md5_process_bytes (&ndx, sizeof (ndx), &ctx);
+ if (td->field_definitions == NULL && td->more_fields == NULL)
+ for (j = 0; j < l->ta[i].count; j++)
+ if (l->ta[i].p[j] && 0)
+ {
+ size_t sz;
+ sz = td->size_fetcher (l->ta[i].p[j], td);
+ md5_process_bytes (&sz, sizeof (sz), &ctx);
+ md5_process_bytes (l->ta[i].p[j], sz, &ctx);
+ }
+ }
+
+ md5_finish_ctx (&ctx, result);
+ memcpy (cksum, result, CHECKSUM_SIZE);
+}
+
+struct pch_header
+{
+ unsigned n[num_type_defs];
+ unsigned max_size;
+ unsigned string_size;
+};
+
+typedef struct pch_reader_context
+{
+ struct pch_header h;
+ unsigned n_constant[num_type_defs];
+ void **r[num_type_defs];
+ int *rv;
+ size_t rvndx;
+ FILE *f;
+ int error;
+}
+ *rctx_t;
+
+static void add_reader_pointer_directly PARAMS ((void **v,
+ type_definition_p td,
+ void *c_v));
+static void correct_pointer PARAMS ((void **v,
+ type_definition_p td, void *c_v));
+static void restore_variable PARAMS ((void **v,
+ type_definition_p td, void *c_v));
+static void read_untyped PARAMS ((void *v, size_t sz, void *ctx));
+
+static void
+add_reader_pointer_directly (v, td, c_v)
+ void **v;
+ type_definition_p td;
+ void *c_v;
+{
+ rctx_t c = (rctx_t) c_v;
+ enum type_index_e i = type_to_type_index (td);
+
+ c->r[i][c->n_constant[i]++] = *v;
+}
+
+static void
+correct_pointer (x, td, c_v)
+ void **x;
+ type_definition_p td;
+ void *c_v;
+{
+ rctx_t c = (rctx_t) c_v;
+ enum type_index_e i = type_to_type_index (td);
+
+#ifdef GT_DEBUG
+fprintf(stderr,"correct_pointer ( x = %p )\n",*x);
+#endif
+ *x = c->r[i][(unsigned) (*x)];
+}
+
+static void
+restore_variable (x, td, c_v)
+ void **x;
+ type_definition_p td;
+ void *c_v;
+{
+ rctx_t c = (rctx_t) c_v;
+ enum type_index_e i = type_to_type_index (td);
+ int xi = c->rv[c->rvndx++];
+
+#ifdef ENABLE_CHECKING
+ if ((td->ggc_p <= 0) && (*x != NULL) && (*x != c->r[i][xi]))
+ warning ("PCH: leaking data structure at %x", *x);
+#endif
+
+ *x = c->r[i][xi];
+}
+
+static void
+read_untyped (v, sz, c_v)
+ void *v;
+ size_t sz;
+ void *c_v;
+{
+ rctx_t c = c_v;
+ if (!c->error)
+ if (fread (v, sz, 1, c->f) != 1)
+ c->error = 1;
+}
+
+
+/* Restore a list. KNOWN and LIST must point to the same list of pointers
+as was originally written. */
+
+int
+read_type_addresses_list (f, known, list)
+ FILE *f;
+ typed_addresses_list_p known;
+ typed_addresses_list_p list;
+{
+ struct pch_reader_context c;
+ char *buf;
+ enum type_index_e i;
+ unsigned j;
+ size_t listsize;
+ void *null = 0;
+
+ memset((void *)&c, 0, sizeof(struct pch_reader_context));
+ /* Read the header from the file. */
+ c.f = f;
+ if (fread (&c.h, sizeof (c.h), 1, c.f) != 1)
+ return -1;
+
+ /* Allocate the main static arrays, initialise the context. */
+ for (i = 0; i < num_type_defs; i++)
+ {
+ c.n_constant[i] = 0;
+ c.r[i] = xcalloc (c.h.n[i], sizeof (void *));
+
+ /* Add NULL pointers for each kind of object. */
+
+ add_reader_pointer_directly (&null, type_index_to_type (i), &c);
+ }
+
+ /* Add the known pointers. */
+ apply_list_pointers (known, add_reader_pointer_directly, &c);
+
+ c.error = 0;
+
+ /* Read in the untyped data. */
+ apply_list_untyped (list, read_untyped, &c);
+
+ if (c.error)
+ return -1;
+
+ buf = xmalloc (c.h.max_size);
+
+ /* Read in the string table. */
+ if (c.h.n[string_type_ndx] > 0)
+ {
+ char *string_table;
+ char *p;
+
+ string_table = xmalloc (c.h.string_size);
+ if (fread (string_table, c.h.string_size, 1, c.f) != 1)
+ return -1;
+
+ p = string_table;
+ i = string_type_ndx;
+ for (j = 1; j < c.h.n[i]; ++j)
+ {
+ int len = strlen (p);
+ c.r[i][j] = (void *)ggc_alloc_string (p, len);
+#ifdef GT_DEBUG
+fprintf(stderr,"Reading (%s)\n",p);
+#endif
+ p += len + 1;
+ }
+
+ if (p != (string_table + c.h.string_size))
+ abort ();
+ free (string_table);
+ }
+
+ /* Read in all the data... */
+ for (i = 0; i < num_type_defs; i++)
+ if (i != string_type_ndx)
+ for (j = c.n_constant[i]; j < c.h.n[i]; j++)
+ {
+ type_definition_p td = type_index_to_type (i);
+ size_t sz, readsize;
+
+ /* Read in enough to be able to determine the type's size. */
+ readsize = td->size;
+ if (readsize != 0 && fread (buf, readsize, 1, c.f) != 1)
+ return -1;
+
+ /* There's a really annoying special case here for
+ TREE_VEC trees. We need more information to be able
+ to determine their size. */
+ if (i == tree_type_ndx && TREE_CODE ((tree) buf) == TREE_VEC)
+ {
+ if (fread (buf + readsize, sizeof (struct tree_vec) - readsize,
+ 1, c.f) != 1)
+ return -1;
+ readsize = sizeof (struct tree_vec);
+ }
+
+ sz = td->size_fetcher (buf, td);
+ if (sz != readsize)
+ if (fread (buf + readsize, sz - readsize, 1, c.f) != 1)
+ return -1;
+
+ /* Handle reading any subobjects. */
+ if (td->subobject_definitions)
+ {
+ subobject_definition_p sd;
+ code_type code = 0;
+
+ if (td->code_fetcher)
+ code = td->code_fetcher (buf);
+ for (sd = td->subobject_definitions;
+ sd->size_fetcher != NULL; sd++)
+ if ((code & sd->mask) == sd->cond)
+ {
+ size_t sz;
+ char *sob;
+
+ if (fgetc (c.f) == 0)
+ {
+ *(char **) (buf + sd->offset) = 0;
+ continue;
+ }
+
+ sz = sd->size_fetcher (buf, td);
+ if (td->ggc_p > 0)
+ sob = ggc_alloc (sz);
+ else
+ sob = xmalloc (sz);
+ if (fread (sob, sz, 1, c.f) != 1)
+ return -1;
+ *(char **) (buf + sd->offset) = sob;
+ }
+ }
+
+ /* IDENTIFIER_NODEs must be canonicalized. Ask
+ get_identifier what the canonical IDENTIFIER_NODE
+ should be. */
+ if (i == tree_type_ndx && TREE_CODE ((tree) buf) == IDENTIFIER_NODE)
+ {
+ tree oldt = (tree) buf;
+ tree t;
+#if 1
+ correct_pointer ((void **)IDENTIFIER_POINTER (oldt),
+ string_type_def, &c);
+#else
+ correct_pointer ((void **) IDENTIFIER_POINTER (oldt),
+ identifier_type_def, &c);
+#endif
+ t = get_identifier (IDENTIFIER_POINTER (oldt));
+
+ TREE_CHAIN (oldt) = TREE_CHAIN (t);
+ c.r[i][j] = t;
+ }
+ else
+ if (td->ggc_p > 0)
+ c.r[i][j] = ggc_alloc (sz);
+ else
+ c.r[i][j] = xmalloc (sz);
+ memcpy (c.r[i][j], buf, sz);
+ }
+ free (buf);
+
+ /* Fix up all the pointers in the just-read structures. */
+ for (i = 0; i < num_type_defs; i++)
+ if (i != string_type_ndx)
+ for (j = c.n_constant[i]; j < c.h.n[i]; j++)
+ {
+ if (i == tree_type_ndx
+ && TREE_CODE ((tree) c.r[i][j]) == IDENTIFIER_NODE)
+ {
+ tree old_chain;
+ const char *old_identifier_pointer;
+
+ /* For IDENTIFIER_NODEs, the IDENTIFIER_POINTER and the
+ TREE_CHAIN are pointers at this point, so save and
+ restore them around the correction. */
+ old_chain = TREE_CHAIN ((tree) c.r[i][j]);
+ old_identifier_pointer = IDENTIFIER_POINTER ((tree) c.r[i][j]);
+ TREE_CHAIN ((tree) c.r[i][j]) = (tree) 0;
+ IDENTIFIER_POINTER ((tree) c.r[i][j]) = (char *) 0; /* FIXME */
+
+ apply_pointer (c.r[i][j], type_index_to_type (i),
+ correct_pointer, &c);
+
+ TREE_CHAIN ((tree) c.r[i][j]) = old_chain;
+ IDENTIFIER_POINTER ((tree) c.r[i][j]) = old_identifier_pointer;/* FIXME */
+ }
+ else
+ apply_pointer (c.r[i][j], type_index_to_type (i), correct_pointer,
+ &c);
+ }
+
+ /* Store the values read into the list. */
+ count_list_pointers (list, &listsize, NULL);
+ c.rv = xmalloc (listsize * sizeof (int));
+ if (fread (c.rv, sizeof (int), listsize, c.f) != listsize)
+ return -1;
+ c.rvndx = 0;
+ apply_list_pointers (list, restore_variable, &c);
+ free (c.rv);
+ for (i = 0; i < num_type_defs; i++)
+ free (c.r[i]);
+
+ return 0;
+}
+
+
+static int pointer_ent_eq PARAMS ((const void *, const void *));
+static hashval_t pointer_ent_hash PARAMS ((const void *));
+static unsigned add_one_pointer PARAMS ((void *v, type_definition_p td,
+ wctx_t ctx));
+static int add_writer_pointer_wrapper PARAMS ((void **v, type_definition_p td,
+ void *ctx));
+static void record_writer_pointer PARAMS ((void **v, type_definition_p td,
+ void *ctx));
+static void add_writer_pointer_directly PARAMS ((void **v,
+ type_definition_p td,
+ void *ctx));
+static int prewrite_pointer PARAMS ((void **, void *));
+static void pickle_pointer PARAMS ((void **v, type_definition_p td,
+ void *ctx));
+static int write_kind PARAMS ((enum type_index_e, wctx_t));
+static void write_untyped PARAMS ((void *v, size_t sz, void *ctx));
+
+static int
+pointer_ent_eq (a_p, b_p)
+ const void *a_p;
+ const void *b_p;
+{
+ const struct pointer_ent *a = (const struct pointer_ent *) a_p;
+ const struct pointer_ent *b = (const struct pointer_ent *) b_p;
+
+ return a->v == b->v && a->td == b->td;
+}
+
+static hashval_t
+pointer_ent_hash (a_p)
+ const void *a_p;
+{
+ const struct pointer_ent *a = (const struct pointer_ent *) a_p;
+
+ return (hashval_t) a->v;
+}
+
+/* Add the object pointer V, of type TD, to the hash table in C, recording
+ its index for later use. */
+
+static unsigned
+add_one_pointer (v, td, c)
+ void *v;
+ type_definition_p td;
+ wctx_t c;
+{
+ struct pointer_ent e;
+ int i = type_to_type_index (td);
+ void **slot;
+
+ e.v = v;
+ e.td = td;
+ e.ndx = c->n[i];
+ slot = htab_find_slot (c->pointer_h, &e, INSERT);
+ if (*slot == NULL)
+ {
+ *slot = ggc_alloc (sizeof (e));
+ memcpy (*slot, &e, sizeof (e));
+ if (td == string_type_def)
+ c->string_size += (v == NULL ? 1 : td->size_fetcher (v, td));
+ c->n[i]++;
+ return e.ndx;
+ }
+ else
+ return ((struct pointer_ent *) *slot)->ndx;
+}
+
+static int
+add_writer_pointer_wrapper (v_p, td, c_v)
+ void **v_p;
+ type_definition_p td;
+ void *c_v;
+{
+ wctx_t c = (void *) c_v;
+ int i = type_to_type_index (td);
+ unsigned old_n = c->n[i];
+ unsigned ndx;
+
+ ndx = add_one_pointer (*v_p, td, c);
+ return ndx == old_n;
+}
+
+static void
+record_writer_pointer (v_p, td, c_v)
+ void **v_p;
+ type_definition_p td;
+ void *c_v;
+{
+ wctx_t c = c_v;
+ int i = type_to_type_index (td);
+ unsigned old_n = c->n[i];
+ unsigned ndx;
+
+ ndx = add_one_pointer (*v_p, td, c);
+ if (ndx == old_n)
+ apply_pointer_recursively (*v_p, td, add_writer_pointer_wrapper, NULL,
+ c_v);
+}
+
+/* Record the indices of the objects pointed to by a variable in the
+ data_to_save list. This must happen after the indices in the hash table
+ are final; i.e. after any sorting done in setup_strtab. */
+
+static void
+record_listed_nodes (v_p, td, c_v)
+ void **v_p;
+ type_definition_p td;
+ void *c_v;
+{
+ wctx_t c = c_v;
+ struct pointer_ent e;
+ struct pointer_ent *p;
+
+ e.v = *v_p;
+ e.td = td;
+ e.ndx = 0; /* ndx should never be used by the lookup. */
+
+ p = (struct pointer_ent *) htab_find (c->pointer_h, &e);
+ if (p == NULL)
+ abort ();
+
+ c->listd[c->listd_ndx++] = p->ndx;
+}
+
+static void
+add_writer_pointer_directly (x_p, td, c_v)
+ void **x_p;
+ type_definition_p td;
+ void *c_v;
+{
+ wctx_t c = (wctx_t) c_v;
+ int i = type_to_type_index (td);
+
+ if (c->n[i] != c->n_constant[i])
+ abort ();
+ add_one_pointer (*x_p, td, c);
+ c->n_constant[i]++;
+ c->n[i] = c->n_constant[i];
+}
+
+static int
+prewrite_pointer (slot, c_v)
+ void **slot;
+ void *c_v;
+{
+ wctx_t c = c_v;
+ const struct pointer_ent *e = (const struct pointer_ent *) *slot;
+ int i = type_to_type_index (e->td);
+ size_t sz = e->v == NULL ? 0 : e->td->size_fetcher (e->v, e->td);
+
+ c->ptrs[i][e->ndx] = e->v;
+
+ if (c->max_size[i] < sz)
+ c->max_size[i] = sz;
+
+ if (e->v && e->td->prewrite_hook)
+ e->td->prewrite_hook (e->v);
+
+ return 1;
+}
+
+/*
+ * Serialize pointer
+ */
+static void
+pickle_pointer (x, td, c_v)
+ void **x;
+ type_definition_p td;
+ void *c_v;
+{
+ wctx_t c = c_v;
+ struct pointer_ent e;
+ struct pointer_ent *p;
+
+ e.v = *x;
+ e.td = td;
+ e.ndx = 0; /* ndx should never be used by the lookup. */
+ p = (struct pointer_ent *) htab_find (c->pointer_h, &e);
+ if (p == NULL)
+ abort ();
+ *x = (void *) p->ndx;
+}
+
+/*
+ * Write out actual data
+ */
+static int
+write_kind (i, c)
+ enum type_index_e i;
+ wctx_t c;
+{
+ type_definition_p td = type_index_to_type (i);
+ unsigned j;
+ const unsigned maxj = c->n[i];
+ char *d = xmalloc (c->max_size[i]);
+
+ for (j = c->n_constant[i]; j < maxj; j++)
+ {
+ const void *x = c->ptrs[i][j];
+ size_t sz = td->size_fetcher (x, td);
+ code_type code = 0;
+
+ memcpy (d, x, sz);
+
+ if (td->code_fetcher)
+ code = td->code_fetcher (d);
+
+ /* Copy any subobjects. */
+ if (td->subobject_definitions)
+ {
+ subobject_definition_p sd;
+
+ for (sd = td->subobject_definitions; sd->size_fetcher != NULL; sd++)
+ if ((code & sd->mask) == sd->cond)
+ {
+ char **loc = (char **) (d + sd->offset);
+
+ if (*loc)
+ {
+ size_t sz = sd->size_fetcher (d, td);
+ char *sob = xmalloc (sz);
+ memcpy (sob, *loc, sz);
+ *loc = sob;
+ }
+ }
+ }
+
+ /* Serialize pointer d */
+ apply_pointer (d, td, pickle_pointer, c);
+
+ if (fwrite (d, sz, 1, c->f) != 1)
+ return -1;
+
+ /* Write any subobjects. */
+ if (td->subobject_definitions)
+ {
+ subobject_definition_p sd;
+
+ for (sd = td->subobject_definitions; sd->size_fetcher != NULL; sd++)
+ if ((code & sd->mask) == sd->cond)
+ {
+ size_t sz = sd->size_fetcher (d, td);
+ char *sob = *(char **) (d + sd->offset);
+ int r;
+
+ if (sob)
+ {
+ r = putc (1, c->f);
+ if (r >= 0)
+ r = fwrite (sob, sz, 1, c->f);
+ free (sob);
+ if (r != 1)
+ return -1;
+ }
+ else
+ {
+ r = putc (0, c->f);
+ if (r < 0)
+ return -1;
+ }
+ }
+ }
+ }
+
+ free (d);
+ return 0;
+}
+
+/*
+ * Write out untyped data
+ */
+static void
+write_untyped (v, sz, c_v)
+ void *v;
+ size_t sz;
+ void *c_v;
+{
+ wctx_t c = c_v;
+ fwrite (v, sz, 1, c->f);
+}
+
+#if 0
+/* FIXME Don't bother sorting the strings until we update to Zack's string
+ table code; otherwise we have no way of guaranteeing increasing
+ addresses when we read the strings back in. */
+
+/* qsort comparison function for sorting pointers by address. */
+
+static int
+pointer_compare (a_p, b_p)
+ const void *a_p;
+ const void *b_p;
+{
+ const void *a = *(const void **) a_p;
+ const void *b = *(const void **) b_p;
+
+ if (a == b)
+ return 0;
+ else if (a < b)
+ return -1;
+ else
+ return 1;
+}
+#endif
+
+/* We have accumulated the strings in c->ptrs like any other object.
+ But we want to treat them specially, in two ways:
+ - We want to read and write them as one large block rather than individual
+ objects, since the only way to determine their length at read time is
+ to search for the null.
+ - We want them to be emitted in ascending address order, so that we can
+ preserve that order for sorted lists in the C and C++ frontends.
+
+ This processing must happen before pickling. */
+
+static void
+setup_strtab (c)
+ wctx_t c;
+{
+ unsigned int i;
+ size_t string_idx;
+ struct pointer_ent e;
+ struct pointer_ent *p;
+ int ndx = string_type_ndx;
+ type_definition_p td = string_type_def;
+
+#if 0
+ /* Sort the strings by address (not alphabetically). */
+ qsort (c->ptrs[ndx] + c->n_constant[ndx],
+ c->n[ndx] - c->n_constant[ndx], sizeof (void *), pointer_compare);
+#endif
+
+ /* Set up the string table. */
+ c->string_table = xcalloc (c->string_size, 1);
+ e.td = string_type_def;
+ e.ndx = 0; /* ndx should never be used by the lookup. */
+
+ /* The NULL pointer will always be at index 0; skip it so we don't need
+ to handle it in the loop. */
+ string_idx = 1;
+ if (c->n_constant[ndx] != 1)
+ abort ();
+ for (i = c->n_constant[ndx]; i < c->n[ndx]; ++i)
+ {
+ const void *ob = c->ptrs[ndx][i];
+ size_t sz = td->size_fetcher (ob, td);
+
+ e.v = ob;
+ p = (struct pointer_ent *) htab_find (c->pointer_h, &e);
+ if (p == NULL)
+ abort ();
+
+ p->ndx = i;
+ memcpy (c->string_table + string_idx, ob, sz);
+ string_idx += sz;
+ }
+}
+
+
+/* Write out a list.
+KNOWN is a list of pointers that need not be written. */
+
+int
+write_type_addresses_list (f, known, list)
+ FILE *f;
+ typed_addresses_list_p known;
+ typed_addresses_list_p list;
+{
+ struct pch_writer_context c;
+ struct pch_header h;
+ int i;
+ size_t listsize;
+ void *null = NULL;
+
+ memset((void *)&c, 0, sizeof(struct pch_writer_context));
+ c.pointer_h = htab_create (2040, pointer_ent_hash, pointer_ent_eq, NULL);
+ c.string_size = 0;
+ for (i = 0; i < num_type_defs; i++)
+ {
+ c.n_constant[i] = 0;
+ c.n[i] = 0;
+ /* Add NULL pointers for each kind of object. */
+ add_writer_pointer_directly (&null, type_index_to_type (i), &c);
+ }
+
+ /* Add the well-known pointers. */
+ apply_list_pointers (known, add_writer_pointer_directly, &c);
+
+ /* Add the data to write; set up the list. */
+ apply_list_pointers (list, record_writer_pointer, &c);
+
+ /* Set up the ptrs[] array. */
+ for (i = 0; i < num_type_defs; i++)
+ {
+ c.ptrs[i] = xcalloc (c.n[i], sizeof (void *));
+ c.max_size[i] = 0;
+ }
+ c.f = f;
+ htab_traverse (c.pointer_h, prewrite_pointer, &c);
+
+ /* Set up the string table. */
+ setup_strtab (&c);
+
+ /* Set up the header. */
+ for (i = 0; i < num_type_defs; i++)
+ h.n[i] = c.n[i];
+
+ /* Don't bother with the initial null. */
+ h.string_size = c.string_size - 1;
+
+ /* Compute the maximum size. */
+ h.max_size = 0;
+ for (i = 0; i < num_type_defs; i++)
+ if (c.max_size[i] > h.max_size)
+ h.max_size = c.max_size[i];
+
+ /* Write out the header. */
+ if (fwrite (&h, sizeof (h), 1, f) != 1)
+ return -1;
+
+ /* Write out the untyped data. */
+ apply_list_untyped (list, write_untyped, &c);
+
+ /* Write out the strings. */
+ if (h.string_size > 0)
+ if (fwrite (c.string_table + 1, h.string_size, 1, f) != 1)
+ return -1;
+
+ /* Write out the actual data. */
+ for (i = 0; i < num_type_defs; i++)
+ if (i != string_type_ndx)
+ write_kind (i, &c);
+
+ for (i = 0; i < num_type_defs; i++)
+ free (c.ptrs[i]);
+
+ /* Record what objects the listed variables point to. */
+ count_list_pointers (list, &listsize, NULL);
+ c.listd = xmalloc (listsize * sizeof (int));
+ c.listd_ndx = 0;
+ apply_list_pointers (list, record_listed_nodes, &c);
+
+ /* Write out LIST. */
+ if (fwrite (c.listd, sizeof (int), listsize, c.f) != listsize)
+ return -1;
+ free (c.listd);
+
+ return 0;
+}
+
+/* Various global variables used by the precompiled header machinery. */
+typed_addresses_list data_to_save;
+typed_addresses_list known_pointers;