+ }
+ d->reorder_fn = NULL;
+
+ d->val = oldval;
+ d->prev_val[1] = oldprevval1;
+ d->prev_val[2] = oldprevval2;
+
+ if (union_p && ! seen_default_p)
+ {
+ oprintf (d->of, "%*sdefault:\n", d->indent, "");
+ oprintf (d->of, "%*s break;\n", d->indent, "");
+ }
+ if (union_p)
+ {
+ oprintf (d->of, "%*s}\n", d->indent, "");
+ d->indent -= 2;
+ }
+ }
+ break;
+
+ case TYPE_LANG_STRUCT:
+ {
+ type_p nt;
+ for (nt = t->u.s.lang_struct; nt; nt = nt->next)
+ if ((d->bitmap & nt->u.s.bitmap) == d->bitmap)
+ break;
+ if (nt == NULL)
+ error_at_line (d->line, "structure `%s' differs between languages",
+ t->u.s.tag);
+ else
+ walk_type (nt, d);
+ }
+ break;
+
+ case TYPE_PARAM_STRUCT:
+ {
+ type_p *oldparam = d->param;
+
+ d->param = t->u.param_struct.param;
+ walk_type (t->u.param_struct.stru, d);
+ d->param = oldparam;
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* process_field routine for marking routines. */
+
+static void
+write_types_process_field (type_p f, const struct walk_type_data *d)
+{
+ const struct write_types_data *wtd;
+ const char *cast = d->needs_cast_p ? "(void *)" : "";
+ wtd = (const struct write_types_data *) d->cookie;
+
+ switch (f->kind)
+ {
+ case TYPE_POINTER:
+ oprintf (d->of, "%*s%s (%s%s", d->indent, "",
+ wtd->subfield_marker_routine, cast, d->val);
+ if (wtd->param_prefix)
+ {
+ oprintf (d->of, ", %s", d->prev_val[3]);
+ if (d->orig_s)
+ {
+ oprintf (d->of, ", gt_%s_", wtd->param_prefix);
+ output_mangled_typename (d->of, d->orig_s);
+ }
+ else
+ oprintf (d->of, ", gt_%sa_%s", wtd->param_prefix, d->prev_val[0]);
+
+ if (f->u.p->kind == TYPE_PARAM_STRUCT
+ && f->u.p->u.s.line.file != NULL)
+ {
+ oprintf (d->of, ", gt_e_");
+ output_mangled_typename (d->of, f);
+ }
+ else if (UNION_OR_STRUCT_P (f)
+ && f->u.p->u.s.line.file != NULL)
+ {
+ oprintf (d->of, ", gt_ggc_e_");
+ output_mangled_typename (d->of, f);
+ }
+ else
+ oprintf (d->of, ", gt_types_enum_last");
+ }
+ oprintf (d->of, ");\n");
+ if (d->reorder_fn && wtd->reorder_note_routine)
+ oprintf (d->of, "%*s%s (%s%s, %s, %s);\n", d->indent, "",
+ wtd->reorder_note_routine, cast, d->val,
+ d->prev_val[3], d->reorder_fn);
+ break;
+
+ case TYPE_STRING:
+ if (wtd->param_prefix == NULL)
+ break;
+
+ case TYPE_STRUCT:
+ case TYPE_UNION:
+ case TYPE_LANG_STRUCT:
+ case TYPE_PARAM_STRUCT:
+ oprintf (d->of, "%*sgt_%s_", d->indent, "", wtd->prefix);
+ output_mangled_typename (d->of, f);
+ oprintf (d->of, " (%s%s);\n", cast, d->val);
+ if (d->reorder_fn && wtd->reorder_note_routine)
+ oprintf (d->of, "%*s%s (%s%s, %s%s, %s);\n", d->indent, "",
+ wtd->reorder_note_routine, cast, d->val, cast, d->val,
+ d->reorder_fn);
+ break;
+
+ case TYPE_SCALAR:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* A subroutine of write_func_for_structure. Write the enum tag for S. */
+
+static void
+output_type_enum (outf_p of, type_p s)
+{
+ if (s->kind == TYPE_PARAM_STRUCT && s->u.s.line.file != NULL)
+ {
+ oprintf (of, ", gt_e_");
+ output_mangled_typename (of, s);
+ }
+ else if (UNION_OR_STRUCT_P (s) && s->u.s.line.file != NULL)
+ {
+ oprintf (of, ", gt_ggc_e_");
+ output_mangled_typename (of, s);
+ }
+ else
+ oprintf (of, ", gt_types_enum_last");
+}
+
+/* For S, a structure that's part of ORIG_S, and using parameters
+ PARAM, write out a routine that:
+ - Takes a parameter, a void * but actually of type *S
+ - If SEEN_ROUTINE returns nonzero, calls write_types_process_field on each
+ field of S or its substructures and (in some cases) things
+ that are pointed to by S.
+*/
+
+static void
+write_func_for_structure (type_p orig_s, type_p s, type_p *param,
+ const struct write_types_data *wtd)
+{
+ const char *fn = s->u.s.line.file;
+ int i;
+ const char *chain_next = NULL;
+ const char *chain_prev = NULL;
+ const char *mark_hook_name = NULL;
+ options_p opt;
+ struct walk_type_data d;
+
+ /* This is a hack, and not the good kind either. */
+ for (i = NUM_PARAM - 1; i >= 0; i--)
+ if (param && param[i] && param[i]->kind == TYPE_POINTER
+ && UNION_OR_STRUCT_P (param[i]->u.p))
+ fn = param[i]->u.p->u.s.line.file;
+
+ memset (&d, 0, sizeof (d));
+ d.of = get_output_file_with_visibility (fn);
+
+ for (opt = s->u.s.opt; opt; opt = opt->next)
+ if (strcmp (opt->name, "chain_next") == 0)
+ chain_next = opt->info;
+ else if (strcmp (opt->name, "chain_prev") == 0)
+ chain_prev = opt->info;
+ else if (strcmp (opt->name, "mark_hook") == 0)
+ mark_hook_name = opt->info;
+
+ if (chain_prev != NULL && chain_next == NULL)
+ error_at_line (&s->u.s.line, "chain_prev without chain_next");
+
+ d.process_field = write_types_process_field;
+ d.cookie = wtd;
+ d.orig_s = orig_s;
+ d.opt = s->u.s.opt;
+ d.line = &s->u.s.line;
+ d.bitmap = s->u.s.bitmap;
+ d.param = param;
+ d.prev_val[0] = "*x";
+ d.prev_val[1] = "not valid postage"; /* Guarantee an error. */
+ d.prev_val[3] = "x";
+ d.val = "(*x)";
+
+ oprintf (d.of, "\n");
+ oprintf (d.of, "void\n");
+ if (param == NULL)
+ oprintf (d.of, "gt_%sx_%s", wtd->prefix, orig_s->u.s.tag);
+ else
+ {
+ oprintf (d.of, "gt_%s_", wtd->prefix);
+ output_mangled_typename (d.of, orig_s);
+ }
+ oprintf (d.of, " (void *x_p)\n");
+ oprintf (d.of, "{\n");
+ oprintf (d.of, " %s %s * %sx = (%s %s *)x_p;\n",
+ s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag,
+ chain_next == NULL ? "const " : "",
+ s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
+ if (chain_next != NULL)
+ oprintf (d.of, " %s %s * xlimit = x;\n",
+ s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
+ if (chain_next == NULL)
+ {
+ oprintf (d.of, " if (%s (x", wtd->marker_routine);
+ if (wtd->param_prefix)
+ {
+ oprintf (d.of, ", x, gt_%s_", wtd->param_prefix);
+ output_mangled_typename (d.of, orig_s);
+ output_type_enum (d.of, orig_s);
+ }
+ oprintf (d.of, "))\n");
+ }
+ else
+ {
+ oprintf (d.of, " while (%s (xlimit", wtd->marker_routine);
+ if (wtd->param_prefix)
+ {
+ oprintf (d.of, ", xlimit, gt_%s_", wtd->param_prefix);
+ output_mangled_typename (d.of, orig_s);
+ output_type_enum (d.of, orig_s);
+ }
+ oprintf (d.of, "))\n");
+ if (mark_hook_name && !wtd->skip_hooks)
+ {
+ oprintf (d.of, " {\n");
+ oprintf (d.of, " %s (xlimit);\n ", mark_hook_name);
+ }
+ oprintf (d.of, " xlimit = (");
+ d.prev_val[2] = "*xlimit";
+ output_escaped_param (&d, chain_next, "chain_next");
+ oprintf (d.of, ");\n");
+ if (mark_hook_name && !wtd->skip_hooks)
+ oprintf (d.of, " }\n");
+ if (chain_prev != NULL)
+ {
+ oprintf (d.of, " if (x != xlimit)\n");
+ oprintf (d.of, " for (;;)\n");
+ oprintf (d.of, " {\n");
+ oprintf (d.of, " %s %s * const xprev = (",
+ s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
+
+ d.prev_val[2] = "*x";
+ output_escaped_param (&d, chain_prev, "chain_prev");
+ oprintf (d.of, ");\n");
+ oprintf (d.of, " if (xprev == NULL) break;\n");
+ oprintf (d.of, " x = xprev;\n");
+ oprintf (d.of, " (void) %s (xprev",
+ wtd->marker_routine);
+ if (wtd->param_prefix)
+ {
+ oprintf (d.of, ", xprev, gt_%s_", wtd->param_prefix);
+ output_mangled_typename (d.of, orig_s);
+ output_type_enum (d.of, orig_s);
+ }
+ oprintf (d.of, ");\n");
+ oprintf (d.of, " }\n");
+ }
+ oprintf (d.of, " while (x != xlimit)\n");
+ }
+ oprintf (d.of, " {\n");
+ if (mark_hook_name && chain_next == NULL && !wtd->skip_hooks)
+ {
+ oprintf (d.of, " %s (x);\n", mark_hook_name);
+ }
+ d.prev_val[2] = "*x";
+ d.indent = 6;
+ walk_type (s, &d);
+
+ if (chain_next != NULL)
+ {
+ oprintf (d.of, " x = (");
+ output_escaped_param (&d, chain_next, "chain_next");
+ oprintf (d.of, ");\n");
+ }
+
+ oprintf (d.of, " }\n");
+ oprintf (d.of, "}\n");
+}
+
+/* Write out marker routines for STRUCTURES and PARAM_STRUCTS. */
+
+static void
+write_types (type_p structures, type_p param_structs,
+ const struct write_types_data *wtd)
+{
+ type_p s;
+
+ oprintf (header_file, "\n/* %s*/\n", wtd->comment);
+ for (s = structures; s; s = s->next)
+ if (s->gc_used == GC_POINTED_TO
+ || s->gc_used == GC_MAYBE_POINTED_TO)
+ {
+ options_p opt;
+
+ if (s->gc_used == GC_MAYBE_POINTED_TO
+ && s->u.s.line.file == NULL)
+ continue;
+
+ oprintf (header_file, "#define gt_%s_", wtd->prefix);
+ output_mangled_typename (header_file, s);
+ oprintf (header_file, "(X) do { \\\n");
+ oprintf (header_file,
+ " if (X != NULL) gt_%sx_%s (X);\\\n", wtd->prefix,
+ s->u.s.tag);
+ oprintf (header_file,
+ " } while (0)\n");
+
+ for (opt = s->u.s.opt; opt; opt = opt->next)
+ if (strcmp (opt->name, "ptr_alias") == 0)
+ {
+ const_type_p const t = (const_type_p) opt->info;
+ if (t->kind == TYPE_STRUCT
+ || t->kind == TYPE_UNION
+ || t->kind == TYPE_LANG_STRUCT)
+ oprintf (header_file,
+ "#define gt_%sx_%s gt_%sx_%s\n",
+ wtd->prefix, s->u.s.tag, wtd->prefix, t->u.s.tag);
+ else
+ error_at_line (&s->u.s.line,
+ "structure alias is not a structure");
+ break;
+ }
+ if (opt)
+ continue;
+
+ /* Declare the marker procedure only once. */
+ oprintf (header_file,
+ "extern void gt_%sx_%s (void *);\n",
+ wtd->prefix, s->u.s.tag);
+
+ if (s->u.s.line.file == NULL)
+ {
+ fprintf (stderr, "warning: structure `%s' used but not defined\n",
+ s->u.s.tag);
+ continue;
+ }
+
+ if (s->kind == TYPE_LANG_STRUCT)
+ {
+ type_p ss;
+ for (ss = s->u.s.lang_struct; ss; ss = ss->next)
+ write_func_for_structure (s, ss, NULL, wtd);
+ }
+ else
+ write_func_for_structure (s, s, NULL, wtd);
+ }
+
+ for (s = param_structs; s; s = s->next)
+ if (s->gc_used == GC_POINTED_TO)
+ {
+ type_p * param = s->u.param_struct.param;
+ type_p stru = s->u.param_struct.stru;
+
+ /* Declare the marker procedure. */
+ oprintf (header_file, "extern void gt_%s_", wtd->prefix);
+ output_mangled_typename (header_file, s);
+ oprintf (header_file, " (void *);\n");
+
+ if (stru->u.s.line.file == NULL)
+ {
+ fprintf (stderr, "warning: structure `%s' used but not defined\n",
+ s->u.s.tag);
+ continue;
+ }
+
+ if (stru->kind == TYPE_LANG_STRUCT)
+ {
+ type_p ss;
+ for (ss = stru->u.s.lang_struct; ss; ss = ss->next)
+ write_func_for_structure (s, ss, param, wtd);
+ }
+ else
+ write_func_for_structure (s, stru, param, wtd);
+ }
+}
+
+static const struct write_types_data ggc_wtd =
+{
+ "ggc_m", NULL, "ggc_mark", "ggc_test_and_set_mark", NULL,
+ "GC marker procedures. ",
+ FALSE
+};