From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 9299 invoked by alias); 8 Aug 2012 19:53:35 -0000 Received: (qmail 9284 invoked by uid 22791); 8 Aug 2012 19:53:27 -0000 X-SWARE-Spam-Status: No, hits=-2.0 required=5.0 tests=AWL,BAYES_50,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,KAM_STOCKGEN,KHOP_RCVD_TRUST,RCVD_IN_DNSWL_LOW,RCVD_IN_HOSTKARMA_YE,TW_CX,TW_WT,TW_YY,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mail-ob0-f201.google.com (HELO mail-ob0-f201.google.com) (209.85.214.201) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 08 Aug 2012 19:53:05 +0000 Received: by obbun3 with SMTP id un3so762045obb.2 for ; Wed, 08 Aug 2012 12:53:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=date:from:to:subject:message-id:mime-version:content-type :content-disposition:organization:user-agent:x-gm-message-state; bh=C7J5G64DDSo0nZVQPODSfaNnkVqRmX9BJ8lPFXR6VXc=; b=cDgqxtBXhASUUZr/Jg5DCRp9lM+H3jD5zkyEVCgCugZ/PkPBtbuMnboFz22E/iEFf6 Abwwp0Tb0OhB1O2S7zZA+JKSupgb4vTUiblUZFUesVA5KUHHZlbN69N28r+Olqg/U0zF 4pCtM5qG7JwbOcX/eyaucNKHfCCZnnQ4vHHUy1WzzuaDZHEkfLQfSPF0KPRO+EcGDMBa 8nqWEav7HI7LFpwP0bzhPu2gv1XZt68hpgvB9+BmYmBRpqg64PYC6oATlPcgOfxUym5L LkwjuGdTYJc2/KiPQd7NQo/yjOoAMBLEoDxx50Nu7KixUaMD3ScnRf1cfTidv4kXm7/o /xVQ== Received: by 10.43.18.67 with SMTP id qf3mr645830icb.18.1344455584103; Wed, 08 Aug 2012 12:53:04 -0700 (PDT) Received: by 10.43.18.67 with SMTP id qf3mr645824icb.18.1344455584004; Wed, 08 Aug 2012 12:53:04 -0700 (PDT) Received: from wpzn3.hot.corp.google.com (216-239-44-65.google.com [216.239.44.65]) by gmr-mx.google.com with ESMTPS id s10si995422igs.0.2012.08.08.12.53.03 (version=TLSv1/SSLv3 cipher=AES128-SHA); Wed, 08 Aug 2012 12:53:04 -0700 (PDT) Received: from torture.tor.corp.google.com (torture.tor.corp.google.com [172.29.41.4]) by wpzn3.hot.corp.google.com (Postfix) with ESMTP id 6517C100047; Wed, 8 Aug 2012 12:53:03 -0700 (PDT) Received: by torture.tor.corp.google.com (Postfix, from userid 54752) id 852D8C06CD; Wed, 8 Aug 2012 15:52:59 -0400 (EDT) Date: Wed, 08 Aug 2012 19:53:00 -0000 From: Diego Novillo To: gcc-patches@gcc.gnu.org, laurynas.biveinis@gmail.com, Lawrence Crowl Subject: [cxx-conversion] Support garbage-collected C++ templates Message-ID: <20120808195258.GA30576@google.com> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-Gm-Message-State: ALoCoQkYKW03imLBvqX499P1bLkW+5BP+V+1o8BthBwLrVefS9dWz8oMWjbeXHPrBJrdxWgFi/l5CusERnfxjf0MmLhWX8Tv2djoRa3xbThzYCPlwEuTBihHQP4nbVUX/MUAwz91ODvqVuSpaijZZaLENmQlIxMelGvfGwbjv2Vl8i0vi7Jt5P2yy95ZXwIiNxzHu8rPqKbNdIELWXDJfkRIttBKO8zB0Oqok9iDB+zD9p3bGHUsBRs= X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2012-08/txt/msg00464.txt.bz2 Support garbage-collected C++ templates. This patch is the first step towards supporting user-defined GC and PCH marking routines. The patch introduces two major changes: - Support in gengtype for a new type of structure TYPE_USER_STRUCT. This makes gengtype to rely on external marking functions provided by the user. - Support for C++ templates. Templates must rely on user-provided functions because gengtype does not know how to deal with specific instances (nor should it). This allowed me to remove the hack that had been added to support VEC. In vec.h, I added 4 functions that gengtype relies on to do the various marking actions for GGC and PCH. There are some limitations with this patch that I will remove after this is merged into mainline: 1- We should only ask users to generate 3 marking functions: one for GGC, one for PCH and another one for PCH's local pointer walking. Currently, PCH local pointer walking needs 2: one that takes a type 'T' and walks its fields applying the given operation, another one that takes 'T *' and calls the operation on its address. 2- Only templates are supported for user-provided markers. 3- Types not referenced in template arguments cannot have user-callable entry points. These limitations are due to the way gengtype generates marking code. Most header files do not have actual type information for the types they handle (their signatures take 'void *'), so they are limited to the types known by the source file that includes them. Ideally, all marking code would be overloads for the same function taking different argument types. I started going down that road but I quickly found myself having to add forward references, I could not add type references as arguments, etc. I needed to be able to compare the code generated against existing code, so I decided to postpone a major reorganization of the generated code until later. There are many other things in gengtype that I would like to change. It essentially needs to be killed with fire: - With user-supported marking functions we should be able to remove most GTY() marking options and leave it up to the user to write the little snippets of code that traverse structures. For instance, for vec_t, the attribute 'length' is no longer needed. - gengtype currently emits a web of functions that call macros that call functions similarly named. All that is largely unnecessary. It should emit proper C++ overloads. - Functions should be emitted in files that have access to the structure where they were defined. I'm not convinced that the current multiplicity of gt-*.[ch] files is even necessary. However, I would like the guidance of a gengtype maintainer. I don't think I fully understand all of it. I've tested the patch on x86_64 with the page and zone collectors and with --enable-checking=gc,gcac (boy was that a slow mistake). I am now ready to start preparing the merge of the branch into trunk. I will do one final merge from trunk, fix gengtype conflicts from Laurynas's latest change and start sending the merge patches. Committed to cxx-conversion branch. 2012-08-08 Diego Novillo * coretypes.h (gt_pointer_operator): Move from ... * ggc.h: ... here. * doc/gty.texi: Document support for C++ templates and user-provided markers. * gcc/gengtype-lex.l: Update copyright year. Remove support for recognizing DEF_VEC_O, DEF_VEC_P and DEFVEC_I. * gengtype-parse.c: Update copyright year. (token_names): Remove DEF_VEC_O, DEF_VEC_P and DEF_VEC_I. (require_template_declaration): New. (typedef_name): Call it. (type): Replace IS_UNION with KIND. Replace all users. (def_vec): Remove. Update all users. * gengtype-state.c (type_lineloc): Handle TYPE_USER_STRUCT. (write_state_user_struct_type): New. (write_state_type): Call it. (read_state_user_struct_type): New. (read_state_type): Call it. * gengtype.c: Update copyright year. (dump_pair): Move declaration to the top. (dump_type): Likewise. (dump_type_list): Likewise. (dbgprint_count_type_at): Handle TYPE_USER_STRUCT. (create_user_defined_type): New. (resolve_typedef): Call it. (new_structure): Replace argument ISUNION with KIND. Change users to refer to KIND directly. Update all callers. (find_structure): Likewise. (set_gc_used_type): Handle TYPE_USER_STRUCT. (create_file): Update HDR to include new copyright year. (struct walk_type_data): Add field IN_PTR_FIELD. (output_mangled_typename): Handle TYPE_USER_STRUCT. (walk_type): Set D->IN_PTR_FILED when walking a TYPE_POINTER. Clear it afterwards. Handle TYPE_USER_STRUCT. (write_types_process_field): Handle TYPE_USER_STRUCT. (get_type_specifier): Move earlier in the file. (write_type_decl): New. (write_marker_function_name): New. (write_user_func_for_structure_ptr): New. (write_user_func_for_structure_body): New. (write_user_marking_functions): New. (write_func_for_structure): Call write_marker_function_name and write_type_decl. Do not call walk_type for TYPE_USER_STRUCT. Emit a call to the user function directly. Call write_user_marking_functions on TYPE_USER_STRUCTs. (write_types_local_user_process_field): New. (write_pch_user_walking_for_structure_body): New. (write_pch_user_walking_functions): New. (write_types_local_process_field): Handle TYPE_USER_STRUCT. (write_local_func_for_structure): Do not call walk_type for TYPE_USER_STRUCT. Instead, emit the call to gt_pch_nx directly. Call write_pch_user_walking_functions for TYPE_USER_STRUCTs. (write_root): Handle TYPE_USER_STRUCT. (vec_prefix_type): Remove. Update all users. (note_def_vec): Remove. Update all users. (dump_typekind): Handle TYPE_USER_STRUCT. (dump_type): Initialize SEEN_TYPES, if needed. Handle TYPE_USER_STRUCT. (dump_everything): Do not initialize SEEN_TYPES. * gengtype.h: Update copyright year. (enum typekind): Add TYPE_USER_STRUCT. (union_or_struct_p): Rename from UNION_OR_STRUCT_P. Convert into function. Add an overload taking const_type_p. Update all callers. (new_structure): Change second field to type enum typekind. Update all users. (find_structure): Likewise. (note_def_vec): Remove. (DEFVEC_OP): Remove. (DEFVEC_I): Remove. * ggc-page.c (gt_ggc_mx): Add entry points for marking 'const char *&', 'unsigned char *&' and 'unsigned char&'. * ggc-zone.c (gt_ggc_mx): Add entry points for marking 'const char *&' and 'unsigned char *&'. * stringpool.c (gt_pch_nx): Add entry points for marking 'const char *&', 'unsigned char *&' and 'unsigned char&'. Add an entry point for the overload taking arguments 'unsigned char *', 'gt_pointer_operator' and 'void *'. * vec.h (struct vec_prefix): Remove GTY marker. (struct vec_t): Remove GTY((length)) attribute from field 'vec'. (gt_ggc_mx (vec_t *)): New template function. (gt_pch_nx (vec_t *)): New template function. (gt_pch_nx (vec_t *, gt_pointer_operator, void *)): New template function. (gt_pch_nx (vec_t *, gt_pointer_operator, void *)): New template function. diff --git a/gcc/coretypes.h b/gcc/coretypes.h index 02578f6..a2ca9c8 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -196,5 +196,9 @@ enum memmodel /* Suppose that higher bits are target dependant. */ #define MEMMODEL_MASK ((1<<16)-1) +/* Support for user-provided GGC and PCH markers. The first parameter + is a pointer to a pointer, the second a cookie. */ +typedef void (*gt_pointer_operator) (void *, void *); + #endif /* coretypes.h */ diff --git a/gcc/ggc.h b/gcc/ggc.h index d90eec2..5bfbab8 100644 --- a/gcc/ggc.h +++ b/gcc/ggc.h @@ -32,9 +32,6 @@ extern const char empty_string[]; /* empty string */ /* Internal functions and data structures used by the GTY machinery, including the generated gt*.[hc] files. */ -/* The first parameter is a pointer to a pointer, the second a cookie. */ -typedef void (*gt_pointer_operator) (void *, void *); - #include "gtype-desc.h" /* One of these applies its third parameter (with cookie in the fourth diff --git a/gcc/doc/gty.texi b/gcc/doc/gty.texi index cff3ffd..472738e 100644 --- a/gcc/doc/gty.texi +++ b/gcc/doc/gty.texi @@ -437,6 +437,82 @@ special case. See @file{gengtype.c} for further details. Avoid adding new special cases unless there is no other alternative. @end table +@section Support for user-provided GC marking routines +The garbage collector supports types for which no automatic marking +code is generated. For these types, the user is required to provide +four functions: one to act as a marker for garbage collection, and +three functions to act as marker and pointer walking for pre-compiled +headers. + +User-provided types are currently supported for C++ template +structures. When a template type @code{TP} is marked with @code{GTY}, +all instances of that type are considered user-provided types. As +such, the user needs to provide template functions to mark all the +fields of the type. + +The following code snippets represent all the functions that need to +be provided. Note that type @code{TP} may reference to more than one +type. In these snippets, there is only one type @code{T}, but there +could be more. + +@smallexample +template +void gt_ggc_mx (TP *tp) +@{ + extern void gt_ggc_mx (T&); + + /* This marks field 'fld' of type 'T'. */ + gt_ggc_mx (tp->fld); +@} + +template +void gt_pch_nx (TP *tp) +@{ + extern void gt_pch_nx (T&); + + /* This marks field 'fld' of type 'T'. */ + gt_pch_nx (tp->fld); +@} + +template +void gt_pch_nx (TP *tp, gt_pointer_operator op, void *cookie) +@{ + /* For every field 'fld' of 'tp' with type 'T *', call the given + pointer operator. */ + op (&(tp->fld), cookie); +@} + +template +void gt_pch_nx (TP *tp, gt_pointer_operator, void *cookie) +@{ + extern void gt_pch_nx (T *, gt_pointer_operator, void *); + + /* For every field 'fld' of 'tp' with type 'T', call the pointer + walker for all the fields of T. */ + gt_pch_nx (&(tp->fld), op, cookie); +@} +@end smallexample + +Support for user-defined types is currently limited. The following +restrictions apply: + +@enumerate +@item Type @code{TP} and all the argument types @code{T} must be +marked with @code{GTY}. + +@item Type @code{TP} can only have type names in its argument list. + +@item The pointer walker functions are different for @code{TP} and +@code{TP}. In the case of @code{TP}, references to +@code{T} must be handled by calling @code{gt_pch_nx} (which +will, in turn, walk all the pointers inside fields of @code{T}). +In the case of @code{TP}, references to @code{T *} must be +handled by calling the @code{op} function on the address of the +pointer (see the code snippets above). + +@item Only template structures are supported at this time. +@end enumerate + @node GGC Roots @section Marking Roots for the Garbage Collector @cindex roots, marking diff --git a/gcc/gengtype-lex.l b/gcc/gengtype-lex.l index edfd4a1..537acf6 100644 --- a/gcc/gengtype-lex.l +++ b/gcc/gengtype-lex.l @@ -1,6 +1,6 @@ /* -*- indented-text -*- */ /* Process source files and output type information. - Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -91,15 +91,6 @@ EOID [^[:alnum:]_] BEGIN(in_struct); return STATIC; } - -^{HWS}DEF_VEC_[OP]/{EOID} { - BEGIN(in_struct); - return DEFVEC_OP; -} -^{HWS}DEF_VEC_I/{EOID} { - BEGIN(in_struct); - return DEFVEC_I; -} } { diff --git a/gcc/gengtype-parse.c b/gcc/gengtype-parse.c index 751edc8..b213585 100644 --- a/gcc/gengtype-parse.c +++ b/gcc/gengtype-parse.c @@ -1,5 +1,5 @@ /* Process source files and output type information. - Copyright (C) 2006, 2007, 2010 Free Software Foundation, Inc. + Copyright (C) 2006, 2007, 2010, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -77,8 +77,6 @@ static const char *const token_names[] = { "struct", "enum", "VEC", - "DEF_VEC_[OP]", - "DEF_VEC_I", "...", "ptr_alias", "nested_ptr", @@ -211,28 +209,70 @@ string_seq (void) return s1; } -/* typedef_name: either an ID, or VEC(x,y) which is translated to VEC_x_y. - Use only where VEC(x,y) is legitimate, i.e. in positions where a - typedef name may appear. */ + +/* The caller has detected a template declaration that starts + with TMPL_NAME. Parse up to the closing '>'. This recognizes + simple template declarations of the form ID. + It does not try to parse anything more sophisticated than that. + + Returns the template declaration string "ID". */ + +static const char * +require_template_declaration (const char *tmpl_name) +{ + char *str; + + /* Recognize the opening '<'. */ + require ('<'); + str = concat (tmpl_name, "<", (char *) 0); + + /* Read the comma-separated list of identifiers. */ + while (token () != '>') + { + const char *id = require2 (ID, ','); + if (id == NULL) + id = ","; + str = concat (str, id, (char *) 0); + } + + /* Recognize the closing '>'. */ + require ('>'); + str = concat (str, ">", (char *) 0); + + return str; +} + + +/* typedef_name: either an ID, or VEC(x,y), or a template type + specification of the form ID. + + FIXME cxx-conversion. VEC(x,y) is currently translated to the + template 'vec_t'. This is to support the transition to C++ and + avoid re-writing all the 'VEC(x,y)' declarations in the code. This + needs to be fixed when the branch is merged into trunk. */ + static const char * typedef_name (void) { if (token () == VEC_TOKEN) { - const char *c1, *c2, *r; + const char *c1, *r; advance (); require ('('); c1 = require2 (ID, SCALAR); require (','); - c2 = require (ID); + require (ID); require (')'); r = concat ("vec_t<", c1, ">", (char *) 0); free (CONST_CAST (char *, c1)); - free (CONST_CAST (char *, c2)); return r; } + + const char *id = require (ID); + if (token () == '<') + return require_template_declaration (id); else - return require (ID); + return id; } /* Absorb a sequence of tokens delimited by balanced ()[]{}. */ @@ -734,7 +774,7 @@ type (options_p *optsp, bool nested) GTY_BEFORE_ID, GTY_AFTER_ID } is_gty = NO_GTY; - bool is_union = (token () == UNION); + enum typekind kind = (token () == UNION) ? TYPE_UNION : TYPE_STRUCT; advance (); /* Top-level structures that are not explicitly tagged GTY(()) @@ -775,14 +815,14 @@ type (options_p *optsp, bool nested) advance (); fields = struct_field_seq (); require ('}'); - return new_structure (s, is_union, &lexer_line, fields, opts); + return new_structure (s, kind, &lexer_line, fields, opts); } } else if (token () == '{') consume_balanced ('{', '}'); if (opts) *optsp = opts; - return find_structure (s, is_union); + return find_structure (s, kind); } case ENUM: @@ -890,30 +930,6 @@ extern_or_static (void) } } -/* Definition of a generic VEC structure: - - 'DEF_VEC_[IPO]' '(' id ')' ';' - - Scalar VECs require slightly different treatment than otherwise - - that's handled in note_def_vec, we just pass it along.*/ -static void -def_vec (void) -{ - bool is_scalar = (token () == DEFVEC_I); - const char *type; - - require2 (DEFVEC_OP, DEFVEC_I); - require ('('); - type = require2 (ID, SCALAR); - require (')'); - require (';'); - - if (!type) - return; - - note_def_vec (type, is_scalar, &lexer_line); -} - /* Parse the file FNAME for GC-relevant declarations and definitions. This is the only entry point to this file. */ void @@ -938,11 +954,6 @@ parse_file (const char *fname) typedef_decl (); break; - case DEFVEC_OP: - case DEFVEC_I: - def_vec (); - break; - case EOF_TOKEN: goto eof; diff --git a/gcc/gengtype-state.c b/gcc/gengtype-state.c index d7ea9b4..c94d50b 100644 --- a/gcc/gengtype-state.c +++ b/gcc/gengtype-state.c @@ -51,6 +51,7 @@ type_lineloc (const_type_p ty) case TYPE_STRUCT: case TYPE_UNION: case TYPE_LANG_STRUCT: + case TYPE_USER_STRUCT: return CONST_CAST (struct fileloc*, &ty->u.s.line); case TYPE_PARAM_STRUCT: return CONST_CAST (struct fileloc*, &ty->u.param_struct.line); @@ -798,6 +799,22 @@ write_state_struct_type (type_p current) write_state_type (current->u.s.lang_struct); } +/* Write a GTY user-defined struct type. */ +static void +write_state_user_struct_type (type_p current) +{ + DBGPRINTF ("user_struct type @ %p #%d '%s'", (void *) current, + current->state_number, current->u.s.tag); + fprintf (state_file, "user_struct "); + write_state_common_type_content (current); + if (current->u.s.tag != NULL) + write_state_a_string (current->u.s.tag); + else + fprintf (state_file, "nil"); + write_state_fileloc (type_lineloc (current)); + write_state_fields (current->u.s.fields); +} + /* write a GTY union type. */ static void write_state_union_type (type_p current) @@ -828,7 +845,7 @@ write_state_lang_struct_type (type_p current) DBGPRINTF ("homonymous #%d hty @ %p #%d '%s'", nbhomontype, (void *) hty, hty->state_number, hty->u.s.tag); /* Every member of the homonymous list should have the same tag. */ - gcc_assert (UNION_OR_STRUCT_P (hty)); + gcc_assert (union_or_struct_p (hty)); gcc_assert (hty->u.s.lang_struct == current); if (!homoname) homoname = hty->u.s.tag; @@ -947,6 +964,9 @@ write_state_type (type_p current) case TYPE_STRUCT: write_state_struct_type (current); break; + case TYPE_USER_STRUCT: + write_state_user_struct_type (current); + break; case TYPE_UNION: write_state_union_type (current); break; @@ -1365,6 +1385,42 @@ read_state_struct_type (type_p type) } +/* Read a GTY-ed user-provided struct TYPE. */ + +static void +read_state_user_struct_type (type_p type) +{ + struct state_token_st *t0; + + type->kind = TYPE_USER_STRUCT; + read_state_common_type_content (type); + t0 = peek_state_token (0); + if (state_token_kind (t0) == STOK_STRING) + { + if (state_token_is_name (t0, "nil")) + { + type->u.s.tag = NULL; + DBGPRINTF ("read anonymous struct type @%p #%d", + (void *) type, type->state_number); + } + else + { + type->u.s.tag = xstrdup (t0->stok_un.stok_string); + DBGPRINTF ("read struct type @%p #%d '%s'", + (void *) type, type->state_number, type->u.s.tag); + } + + next_state_tokens (1); + read_state_fileloc (&(type->u.s.line)); + read_state_fields (&(type->u.s.fields)); + } + else + { + fatal_reading_state (t0, "Bad tag in user-struct type"); + } +} + + /* Read a GTY-ed union type. */ static void read_state_union_type (type_p type) @@ -1655,6 +1711,12 @@ read_state_type (type_p *current) next_state_tokens (1); read_state_array_type (*current); } + else if (state_token_is_name (t0, "user_struct")) + { + *current = XCNEW (struct type); + next_state_tokens (1); + read_state_user_struct_type (*current); + } else fatal_reading_state (t0, "bad type in (!type"); } diff --git a/gcc/gengtype.c b/gcc/gengtype.c index 986e3fe..baf2f28 100644 --- a/gcc/gengtype.c +++ b/gcc/gengtype.c @@ -1,5 +1,6 @@ /* Process source files and output type information. - Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, + 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -89,6 +91,10 @@ static const char *get_file_realbasename (const input_file *); static int get_prefix_langdir_index (const char *); static const char *get_file_langdir (const input_file *); + +static void dump_pair (int indent, pair_p p); +static void dump_type (int indent, type_p p); +static void dump_type_list (int indent, type_p p); /* Nonzero iff an error has occurred. */ @@ -166,6 +172,7 @@ dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t) int nb_types = 0, nb_scalar = 0, nb_string = 0; int nb_struct = 0, nb_union = 0, nb_array = 0, nb_pointer = 0; int nb_lang_struct = 0, nb_param_struct = 0; + int nb_user_struct = 0; type_p p = NULL; for (p = t; p; p = p->next) { @@ -181,6 +188,9 @@ dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t) case TYPE_STRUCT: nb_struct++; break; + case TYPE_USER_STRUCT: + nb_user_struct++; + break; case TYPE_UNION: nb_union++; break; @@ -211,6 +221,8 @@ dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t) if (nb_lang_struct > 0 || nb_param_struct > 0) fprintf (stderr, "@@%%@@ %d lang_structs, %d param_structs\n", nb_lang_struct, nb_param_struct); + if (nb_user_struct > 0) + fprintf (stderr, "@@%%@@ %d user_structs\n", nb_user_struct); fprintf (stderr, "\n"); } #endif /* ENABLE_CHECKING */ @@ -539,6 +551,50 @@ do_scalar_typedef (const char *s, struct fileloc *pos) do_typedef (s, &scalar_nonchar, pos); } + +/* Define TYPE_NAME to be a user defined type at location POS. */ + +static type_p +create_user_defined_type (const char *type_name, struct fileloc *pos) +{ + type_p ty = find_structure (type_name, TYPE_USER_STRUCT); + ty->u.s.line = *pos; + ty->u.s.bitmap = get_lang_bitmap (pos->file); + do_typedef (type_name, ty, pos); + + /* If TYPE_NAME specifies a template, create references to the types in the + template by preteding that each type is a field of TY. This is needed to + make sure that the types referenced by the template are marked as used. */ + char *str = xstrdup (type_name); + char *open_bracket = strchr (str, '<'); + if (open_bracket) + { + /* We only accept simple template declarations (see + require_template_declaration), so we only need to parse a + comma-separated list of strings, implicitly assumed to + be type names. */ + char *arg = open_bracket + 1; + char *type_id = strtok (arg, ",>"); + pair_p fields = 0; + while (type_id) + { + /* Create a new field for every type found inside the template + parameter list. */ + const char *field_name = xstrdup (type_id); + type_p arg_type = resolve_typedef (field_name, pos); + fields = create_field_at (fields, arg_type, field_name, 0, pos); + type_id = strtok (0, ",>"); + } + + /* Associate the field list to TY. */ + ty->u.s.fields = fields; + } + free (str); + + return ty; +} + + /* Return the type previously defined for S. Use POS to report errors. */ type_p @@ -548,20 +604,30 @@ resolve_typedef (const char *s, struct fileloc *pos) for (p = typedefs; p != NULL; p = p->next) if (strcmp (p->name, s) == 0) return p->type; - error_at_line (pos, "unidentified type `%s'", s); - return &scalar_nonchar; /* treat as "int" */ + + /* If we did not find a typedef registered, assume this is a name + for a user-defined type which will need to provide its own + marking functions. + + FIXME cxx-conversion. Emit an error once explicit annotations + for marking user types are implemented. */ + return create_user_defined_type (s, pos); } -/* Create and return a new structure with tag NAME (or a union iff - ISUNION is nonzero), at POS with fields FIELDS and options O. */ +/* Create and return a new structure with tag NAME at POS with fields + FIELDS and options O. The KIND of structure must be one of + TYPE_STRUCT, TYPE_UNION or TYPE_USER_STRUCT. */ type_p -new_structure (const char *name, int isunion, struct fileloc *pos, +new_structure (const char *name, enum typekind kind, struct fileloc *pos, pair_p fields, options_p o) { type_p si; type_p s = NULL; lang_bitmap bitmap = get_lang_bitmap (pos->file); + bool isunion = (kind == TYPE_UNION); + + gcc_assert (union_or_struct_p (kind)); for (si = structures; si != NULL; si = si->next) if (strcmp (name, si->u.s.tag) == 0 && UNION_P (si) == isunion) @@ -621,7 +687,7 @@ new_structure (const char *name, int isunion, struct fileloc *pos, error_at_line (&s->u.s.line, "previous definition here"); } - s->kind = isunion ? TYPE_UNION : TYPE_STRUCT; + s->kind = kind; s->u.s.tag = name; s->u.s.line = *pos; s->u.s.fields = fields; @@ -633,14 +699,18 @@ new_structure (const char *name, int isunion, struct fileloc *pos, return s; } -/* Return the previously-defined structure with tag NAME (or a union - iff ISUNION is nonzero), or a new empty structure or union if none - was defined previously. */ +/* Return the previously-defined structure or union with tag NAME, + or a new empty structure or union if none was defined previously. + The KIND of structure must be one of TYPE_STRUCT, TYPE_UNION or + TYPE_USER_STRUCT. */ type_p -find_structure (const char *name, int isunion) +find_structure (const char *name, enum typekind kind) { type_p s; + bool isunion = (kind == TYPE_UNION); + + gcc_assert (union_or_struct_p (kind)); for (s = structures; s != NULL; s = s->next) if (strcmp (name, s->u.s.tag) == 0 && UNION_P (s) == isunion) @@ -651,7 +721,7 @@ find_structure (const char *name, int isunion) s->next = structures; s->state_number = -type_count; structures = s; - s->kind = isunion ? TYPE_UNION : TYPE_STRUCT; + s->kind = kind; s->u.s.tag = name; structures = s; return s; @@ -851,7 +921,7 @@ create_optional_field_ (pair_p next, type_p type, const char *name, union_fields->opt = create_string_option (union_fields->opt, "tag", "1"); union_type = - new_structure (xasprintf ("%s_%d", "fake_union", id++), 1, + new_structure (xasprintf ("%s_%d", "fake_union", id++), TYPE_UNION, &lexer_line, union_fields, NULL); /* Create the field and give it the new fake union type. Add a "desc" @@ -993,16 +1063,16 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt)) nodot = create_string_option (NULL, "dot", ""); - rtx_tp = create_pointer (find_structure ("rtx_def", 0)); - rtvec_tp = create_pointer (find_structure ("rtvec_def", 0)); - tree_tp = create_pointer (find_structure ("tree_node", 1)); - mem_attrs_tp = create_pointer (find_structure ("mem_attrs", 0)); + rtx_tp = create_pointer (find_structure ("rtx_def", TYPE_STRUCT)); + rtvec_tp = create_pointer (find_structure ("rtvec_def", TYPE_STRUCT)); + tree_tp = create_pointer (find_structure ("tree_node", TYPE_UNION)); + mem_attrs_tp = create_pointer (find_structure ("mem_attrs", TYPE_STRUCT)); reg_attrs_tp = - create_pointer (find_structure ("reg_attrs", 0)); + create_pointer (find_structure ("reg_attrs", TYPE_STRUCT)); basic_block_tp = - create_pointer (find_structure ("basic_block_def", 0)); + create_pointer (find_structure ("basic_block_def", TYPE_STRUCT)); constant_tp = - create_pointer (find_structure ("constant_descriptor_rtx", 0)); + create_pointer (find_structure ("constant_descriptor_rtx", TYPE_STRUCT)); scalar_tp = &scalar_nonchar; /* rtunion int */ { @@ -1042,7 +1112,7 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt)) note_flds->opt = create_string_option (nodot, "tag", note_insn_name[c]); } - note_union_tp = new_structure ("rtx_def_note_subunion", 1, + note_union_tp = new_structure ("rtx_def_note_subunion", TYPE_UNION, &lexer_line, note_flds, NULL); } /* Create a type to represent the various forms of SYMBOL_REF_DATA. */ @@ -1052,7 +1122,7 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt)) sym_flds->opt = create_string_option (nodot, "default", ""); sym_flds = create_field (sym_flds, constant_tp, "rt_constant"); sym_flds->opt = create_string_option (nodot, "tag", "1"); - symbol_union_tp = new_structure ("rtx_def_symbol_subunion", 1, + symbol_union_tp = new_structure ("rtx_def_symbol_subunion", TYPE_UNION, &lexer_line, sym_flds, NULL); } for (i = 0; i < NUM_RTX_CODE; i++) @@ -1185,14 +1255,15 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt)) { /* Add the "block_sym" field if SYMBOL_REF_HAS_BLOCK_INFO_P holds. */ - type_p field_tp = find_structure ("block_symbol", 0); + type_p field_tp = find_structure ("block_symbol", TYPE_STRUCT); subfields = create_optional_field (subfields, field_tp, "block_sym", "SYMBOL_REF_HAS_BLOCK_INFO_P (&%0)"); } sname = xasprintf ("rtx_def_%s", rtx_name[i]); - substruct = new_structure (sname, 0, &lexer_line, subfields, NULL); + substruct = new_structure (sname, TYPE_STRUCT, &lexer_line, subfields, + NULL); ftag = xstrdup (rtx_name[i]); for (nmindex = 0; nmindex < strlen (ftag); nmindex++) @@ -1200,7 +1271,8 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt)) flds = create_field (flds, substruct, ""); flds->opt = create_string_option (nodot, "tag", ftag); } - return new_structure ("rtx_def_subunion", 1, &lexer_line, flds, nodot); + return new_structure ("rtx_def_subunion", TYPE_UNION, &lexer_line, flds, + nodot); } /* Handle `special("tree_exp")'. This is a special case for @@ -1229,7 +1301,8 @@ adjust_field_tree_exp (type_p t, options_p opt ATTRIBUTE_UNUSED) "TREE_OPERAND_LENGTH ((tree) &%0)"); flds->opt = create_string_option (flds->opt, "default", ""); - return new_structure ("tree_exp_subunion", 1, &lexer_line, flds, nodot); + return new_structure ("tree_exp_subunion", TYPE_UNION, &lexer_line, flds, + nodot); } /* Perform any special processing on a type T, about to become the type @@ -1265,8 +1338,8 @@ adjust_field_type (type_p t, options_p opt) { int num = ISDIGIT (opt->name[5]) ? opt->name[5] - '0' : 0; - if (!UNION_OR_STRUCT_P (t) - && (t->kind != TYPE_POINTER || !UNION_OR_STRUCT_P (t->u.p))) + if (!union_or_struct_p (t) + && (t->kind != TYPE_POINTER || !union_or_struct_p (t->u.p))) { error_at_line (&lexer_line, "option `%s' may only be applied to structures or structure pointers", @@ -1359,6 +1432,7 @@ set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM]) { case TYPE_STRUCT: case TYPE_UNION: + case TYPE_USER_STRUCT: { pair_p f; int dummy; @@ -1458,7 +1532,7 @@ static outf_p create_file (const char *name, const char *oname) { static const char *const hdr[] = { - " Copyright (C) 2004, 2007, 2009 Free Software Foundation, Inc.\n", + " Copyright (C) 2004, 2007, 2009, 2012 Free Software Foundation, Inc.\n", "\n", "This file is part of GCC.\n", "\n", @@ -2166,7 +2240,6 @@ close_output_files (void) for (of = output_files; of; of = of->next) { - if (!is_file_equal (of)) { FILE *newfile = NULL; @@ -2293,6 +2366,7 @@ struct walk_type_data bool fn_wants_lvalue; bool in_record_p; int loopcounter; + bool in_ptr_field; }; @@ -2349,6 +2423,7 @@ output_mangled_typename (outf_p of, const_type_p t) case TYPE_STRUCT: case TYPE_UNION: case TYPE_LANG_STRUCT: + case TYPE_USER_STRUCT: { const char *id_for_tag = filter_type_name (t->u.s.tag); oprintf (of, "%lu%s", (unsigned long) strlen (id_for_tag), @@ -2412,6 +2487,7 @@ output_escaped_param (struct walk_type_data *d, const char *param, } } + /* Call D->PROCESS_FIELD for every field (or subfield) of D->VAL, which is of type T. Write code to D->OF to constrain execution (at the point that D->PROCESS_FIELD is called) to the appropriate @@ -2492,7 +2568,7 @@ walk_type (type_p t, struct walk_type_data *d) if (pointer_p) t = t->u.p; - if (!UNION_OR_STRUCT_P (t)) + if (!union_or_struct_p (t)) error_at_line (d->line, "`use_params' option on unimplemented type"); else t = find_param_structure (t, d->param); @@ -2520,7 +2596,7 @@ walk_type (type_p t, struct walk_type_data *d) } if (maybe_undef_p - && (t->kind != TYPE_POINTER || !UNION_OR_STRUCT_P (t->u.p))) + && (t->kind != TYPE_POINTER || !union_or_struct_p (t->u.p))) { error_at_line (d->line, "field `%s' has invalid option `maybe_undef_p'\n", @@ -2543,6 +2619,7 @@ walk_type (type_p t, struct walk_type_data *d) case TYPE_POINTER: { + d->in_ptr_field = true; if (maybe_undef_p && t->u.p->u.s.line.file == NULL) { oprintf (d->of, "%*sgcc_assert (!%s);\n", d->indent, "", d->val); @@ -2570,7 +2647,7 @@ walk_type (type_p t, struct walk_type_data *d) if (!length) { - if (!UNION_OR_STRUCT_P (t->u.p) + if (!union_or_struct_p (t->u.p) && t->u.p->kind != TYPE_PARAM_STRUCT) { error_at_line (d->line, @@ -2583,7 +2660,7 @@ walk_type (type_p t, struct walk_type_data *d) { const char *oldprevval2 = d->prev_val[2]; - if (!UNION_OR_STRUCT_P (nested_ptr_d->type)) + if (!union_or_struct_p (nested_ptr_d->type)) { error_at_line (d->line, "field `%s' has invalid " @@ -2657,6 +2734,7 @@ walk_type (type_p t, struct walk_type_data *d) d->indent -= 2; oprintf (d->of, "%*s}\n", d->indent, ""); } + d->in_ptr_field = false; } break; @@ -2940,6 +3018,10 @@ walk_type (type_p t, struct walk_type_data *d) } break; + case TYPE_USER_STRUCT: + d->process_field (t, d); + break; + default: gcc_unreachable (); } @@ -2997,7 +3079,7 @@ write_types_process_field (type_p f, const struct walk_type_data *d) 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) + 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); @@ -3017,13 +3099,27 @@ write_types_process_field (type_p f, const struct walk_type_data *d) 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); + case TYPE_USER_STRUCT: + if (f->kind == TYPE_USER_STRUCT && !d->in_ptr_field) + { + /* If F is a user-defined type and the field is not a + pointer to the type, then we should not generate the + standard pointer-marking code. All we need to do is call + the user-provided marking function to process the fields + of F. */ + oprintf (d->of, "%*sgt_%sx (&(%s));\n", d->indent, "", wtd->prefix, + d->val); + } + else + { + 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: @@ -3044,7 +3140,7 @@ output_type_enum (outf_p of, type_p s) oprintf (of, ", gt_e_"); output_mangled_typename (of, s); } - else if (UNION_OR_STRUCT_P (s) && s->u.s.line.file != NULL) + else if (union_or_struct_p (s) && s->u.s.line.file != NULL) { oprintf (of, ", gt_ggc_e_"); output_mangled_typename (of, s); @@ -3062,13 +3158,13 @@ get_output_file_for_structure (const_type_p s, type_p *param) const input_file *fn; int i; - gcc_assert (UNION_OR_STRUCT_P (s)); + gcc_assert (union_or_struct_p (s)); fn = s->u.s.line.file; /* 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)) + && union_or_struct_p (param[i]->u.p)) fn = param[i]->u.p->u.s.line.file; /* The call to get_output_file_with_visibility may update fn by @@ -3076,13 +3172,185 @@ get_output_file_for_structure (const_type_p s, type_p *param) return get_output_file_with_visibility (CONST_CAST (input_file*, fn)); } + +/* Returns the specifier keyword for a string or union type S, empty string + otherwise. */ + +static const char * +get_type_specifier (const type_p s) +{ + if (s->kind == TYPE_STRUCT) + return "struct "; + else if (s->kind == TYPE_LANG_STRUCT) + return get_type_specifier (s->u.s.lang_struct); + else if (s->kind == TYPE_UNION) + return "union "; + return ""; +} + + +/* Emits a declaration for type TY (assumed to be a union or a + structure) on stream OUT. */ + +static void +write_type_decl (outf_p out, type_p ty) +{ + if (union_or_struct_p (ty)) + oprintf (out, "%s%s", get_type_specifier (ty), ty->u.s.tag); + else if (ty->kind == TYPE_SCALAR) + { + if (ty->u.scalar_is_char) + oprintf (out, "const char"); + else + oprintf (out, "void"); + } + else if (ty->kind == TYPE_POINTER) + { + write_type_decl (out, ty->u.p); + oprintf (out, " *"); + } + else if (ty->kind == TYPE_ARRAY) + { + write_type_decl (out, ty->u.a.p); + oprintf (out, " *"); + } + else if (ty->kind == TYPE_STRING) + { + oprintf (out, "const char *"); + } + else + gcc_unreachable (); +} + + +/* Write on OF the name of the marker function for structure S. PREFIX + is the prefix to use (to distinguish ggc from pch markers). */ + +static void +write_marker_function_name (outf_p of, type_p s, const char *prefix) +{ + if (union_or_struct_p (s)) + { + const char *id_for_tag = filter_type_name (s->u.s.tag); + oprintf (of, "gt_%sx_%s", prefix, id_for_tag); + if (id_for_tag != s->u.s.tag) + free (CONST_CAST(char *, id_for_tag)); + } + else if (s->kind == TYPE_PARAM_STRUCT) + { + oprintf (of, "gt_%s_", prefix); + output_mangled_typename (of, s); + } + else + gcc_unreachable (); +} + + +/* Write on OF a user-callable routine to act as an entry point for + the marking routine for S, generated by write_func_for_structure. + PREFIX is the prefix to use to distinguish ggc and pch markers. */ + +static void +write_user_func_for_structure_ptr (outf_p of, type_p s, const char *prefix) +{ + /* Parameterized structures are not supported in user markers. There + is no way for the marker function to know which specific type + to use to generate the call to the void * entry point. For + instance, a marker for struct htab may need to call different + routines to mark the fields, depending on the paramN_is attributes. + + A user-defined marker that accepts 'struct htab' as its argument + would not know which variant to call. Generating several entry + points accepting 'struct htab' would cause multiply-defined + errors during compilation. */ + gcc_assert (union_or_struct_p (s)); + + type_p alias_of = NULL; + for (options_p opt = s->u.s.opt; opt; opt = opt->next) + if (strcmp (opt->name, "ptr_alias") == 0) + { + /* ALIAS_OF is set if ORIG_S is marked "ptr_alias". This means that + we do not generate marking code for ORIG_S here. Instead, a + forwarder #define in gtype-desc.h will cause every call to its + marker to call the target of this alias. + + However, we still want to create a user entry code for the + aliased type. So, if ALIAS_OF is set, we only generate the + user-callable marker function. */ + alias_of = opt->info.type; + break; + } + + oprintf (of, "\nvoid\n"); + oprintf (of, "gt_%sx (", prefix); + write_type_decl (of, s); + oprintf (of, " *& x)\n"); + oprintf (of, "{\n"); + oprintf (of, " if (x)\n "); + write_marker_function_name (of, alias_of ? alias_of : s, prefix); + oprintf (of, " ((void *) x);\n"); + oprintf (of, "}\n"); +} + + +/* Write a function to mark all the fields of type S on OF. PREFIX + and D are as in write_user_marking_functions. */ + +static void +write_user_func_for_structure_body (type_p s, const char *prefix, + struct walk_type_data *d) +{ + oprintf (d->of, "\nvoid\n"); + oprintf (d->of, "gt_%sx (", prefix); + write_type_decl (d->of, s); + oprintf (d->of, "& x_r ATTRIBUTE_UNUSED)\n"); + oprintf (d->of, "{\n"); + oprintf (d->of, " "); + write_type_decl (d->of, s); + oprintf (d->of, " * ATTRIBUTE_UNUSED x = &x_r;\n"); + d->val = "(*x)"; + d->indent = 2; + walk_type (s, d); + oprintf (d->of, "}\n"); +} + + +/* Emit the user-callable functions needed to mark all the types used + by the user structure S. PREFIX is the prefix to use to + distinguish ggc and pch markers. D contains data needed to pass to + walk_type when traversing the fields of a type. + + For every type T referenced by S, two routines are generated: one + that takes 'T *', marks the pointer and calls the second routine, + which just marks the fields of T. */ + +static void +write_user_marking_functions (type_p s, const char *prefix, + struct walk_type_data *d) +{ + gcc_assert (s->kind == TYPE_USER_STRUCT); + + for (pair_p fld = s->u.s.fields; fld; fld = fld->next) + { + type_p fld_type = fld->type; + if (fld_type->kind == TYPE_POINTER) + { + type_p pointed_to_type = fld_type->u.p; + if (union_or_struct_p (pointed_to_type)) + write_user_func_for_structure_ptr (d->of, pointed_to_type, prefix); + } + else if (union_or_struct_p (fld_type)) + write_user_func_for_structure_body (fld_type, prefix, d); + } +} + + /* 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. -*/ + that are pointed to by S. */ static void write_func_for_structure (type_p orig_s, type_p s, type_p *param, @@ -3131,27 +3399,19 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param, oprintf (d.of, "\n"); oprintf (d.of, "void\n"); - if (param == NULL) - { - const char *id_for_tag = filter_type_name (orig_s->u.s.tag); - oprintf (d.of, "gt_%sx_%s", wtd->prefix, id_for_tag); - if (id_for_tag != orig_s->u.s.tag) - free (CONST_CAST(char *, id_for_tag)); - } - else - { - oprintf (d.of, "gt_%s_", wtd->prefix); - output_mangled_typename (d.of, orig_s); - } + write_marker_function_name (d.of, orig_s, wtd->prefix); 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); + oprintf (d.of, "{\n "); + write_type_decl (d.of, s); + oprintf (d.of, " * %sx = (", chain_next == NULL ? "const " : ""); + write_type_decl (d.of, s); + oprintf (d.of, " *)x_p;\n"); if (chain_next != NULL) - oprintf (d.of, " %s %s * xlimit = x;\n", - s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag); + { + oprintf (d.of, " "); + write_type_decl (d.of, s); + oprintf (d.of, " * xlimit = x;\n"); + } if (chain_next == NULL) { oprintf (d.of, " if (%s (x", wtd->marker_routine); @@ -3234,9 +3494,17 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param, { oprintf (d.of, " %s (x);\n", mark_hook_name); } + d.prev_val[2] = "*x"; d.indent = 6; - walk_type (s, &d); + if (orig_s->kind != TYPE_USER_STRUCT) + walk_type (s, &d); + else + { + /* User structures have no fields to walk. Simply generate a call + to the user-provided structure marker. */ + oprintf (d.of, "%*sgt_%sx (x);\n", d.indent, "", wtd->prefix); + } if (chain_next != NULL) { @@ -3249,8 +3517,12 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param, if (chain_circular != NULL) oprintf (d.of, " while (x != xlimit);\n"); oprintf (d.of, "}\n"); + + if (orig_s->kind == TYPE_USER_STRUCT) + write_user_marking_functions (orig_s, wtd->prefix, &d); } + /* Write out marker routines for STRUCTURES and PARAM_STRUCTS. */ static void @@ -3261,9 +3533,10 @@ write_types (outf_p output_header, type_p structures, type_p param_structs, type_p s; oprintf (output_header, "\n/* %s*/\n", wtd->comment); + /* We first emit the macros and the declarations. Functions' code is emitted afterwards. This is needed in plugin mode. */ - oprintf (output_header, "/* macros and declarations */\n"); + oprintf (output_header, "/* Macros and declarations. */\n"); for (s = structures; s; s = s->next) if (s->gc_used == GC_POINTED_TO || s->gc_used == GC_MAYBE_POINTED_TO) { @@ -3434,6 +3707,90 @@ static const struct write_types_data pch_wtd = { /* Write out the local pointer-walking routines. */ +/* process_field routine for local pointer-walking for user-callable + routines. The difference between this and + write_types_local_process_field is that, in this case, we do not + need to check whether the given pointer matches the address of the + parent structure. This check was already generated by the call + to gt_pch_nx in the main gt_pch_p_*() function that is calling + this code. */ + +static void +write_types_local_user_process_field (type_p f, const struct walk_type_data *d) +{ + switch (f->kind) + { + case TYPE_POINTER: + case TYPE_STRUCT: + case TYPE_UNION: + case TYPE_LANG_STRUCT: + case TYPE_PARAM_STRUCT: + case TYPE_STRING: + oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); + break; + + case TYPE_USER_STRUCT: + if (d->in_ptr_field) + oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); + else + oprintf (d->of, "%*s gt_pch_nx (&(%s), op, cookie);\n", + d->indent, "", d->val); + break; + + case TYPE_SCALAR: + break; + + default: + gcc_unreachable (); + } +} + + +/* Write a function to PCH walk all the fields of type S on OF. + D contains data needed by walk_type to recurse into the fields of S. */ + +static void +write_pch_user_walking_for_structure_body (type_p s, struct walk_type_data *d) +{ + oprintf (d->of, "\nvoid\n"); + oprintf (d->of, "gt_pch_nx ("); + write_type_decl (d->of, s); + oprintf (d->of, "* x ATTRIBUTE_UNUSED,\n" + "\tATTRIBUTE_UNUSED gt_pointer_operator op,\n" + "\tATTRIBUTE_UNUSED void *cookie)\n"); + oprintf (d->of, "{\n"); + d->val = "(*x)"; + d->indent = 2; + d->process_field = write_types_local_user_process_field; + walk_type (s, d); + oprintf (d->of, "}\n"); +} + + +/* Emit the user-callable functions needed to mark all the types used + by the user structure S. PREFIX is the prefix to use to + distinguish ggc and pch markers. CHAIN_NEXT is set if S has the + chain_next option defined. D contains data needed to pass to + walk_type when traversing the fields of a type. + + For every type T referenced by S, two routines are generated: one + that takes 'T *', marks the pointer and calls the second routine, + which just marks the fields of T. */ + +static void +write_pch_user_walking_functions (type_p s, struct walk_type_data *d) +{ + gcc_assert (s->kind == TYPE_USER_STRUCT); + + for (pair_p fld = s->u.s.fields; fld; fld = fld->next) + { + type_p fld_type = fld->type; + if (union_or_struct_p (fld_type)) + write_pch_user_walking_for_structure_body (fld_type, d); + } +} + + /* process_field routine for local pointer-walking. */ static void @@ -3452,6 +3809,16 @@ write_types_local_process_field (type_p f, const struct walk_type_data *d) oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); break; + case TYPE_USER_STRUCT: + oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "", + d->prev_val[3]); + if (d->in_ptr_field) + oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); + else + oprintf (d->of, "%*s gt_pch_nx (&(%s), op, cookie);\n", + d->indent, "", d->val); + break; + case TYPE_SCALAR: break; @@ -3460,6 +3827,7 @@ write_types_local_process_field (type_p f, const struct walk_type_data *d) } } + /* For S, a structure that's part of ORIG_S, and using parameters PARAM, write out a routine that: - Is of type gt_note_pointers @@ -3493,12 +3861,27 @@ write_local_func_for_structure (const_type_p orig_s, type_p s, type_p *param) "\tATTRIBUTE_UNUSED gt_pointer_operator op,\n" "\tATTRIBUTE_UNUSED void *cookie)\n"); oprintf (d.of, "{\n"); - oprintf (d.of, " %s %s * const x ATTRIBUTE_UNUSED = (%s %s *)x_p;\n", + oprintf (d.of, " %s %s * x ATTRIBUTE_UNUSED = (%s %s *)x_p;\n", s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag, s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag); d.indent = 2; - walk_type (s, &d); + if (s->kind != TYPE_USER_STRUCT) + walk_type (s, &d); + else + { + /* User structures have no fields to walk. Simply generate a + call to the user-provided PCH walker. */ + oprintf (d.of, "%*sif ((void *)(%s) == this_obj)\n", d.indent, "", + d.prev_val[3]); + oprintf (d.of, "%*s gt_pch_nx (&(%s), op, cookie);\n", + d.indent, "", d.val); + } + oprintf (d.of, "}\n"); + + /* Write user-callable entry points for the PCH walking routines. */ + if (orig_s->kind == TYPE_USER_STRUCT) + write_pch_user_walking_functions (s, &d); } /* Write out local marker routines for STRUCTURES and PARAM_STRUCTS. */ @@ -3510,6 +3893,7 @@ write_local (outf_p output_header, type_p structures, type_p param_structs) if (!output_header) return; + oprintf (output_header, "\n/* Local pointer-walking routines. */\n"); for (s = structures; s; s = s->next) if (s->gc_used == GC_POINTED_TO || s->gc_used == GC_MAYBE_POINTED_TO) @@ -3589,15 +3973,15 @@ write_local (outf_p output_header, type_p structures, type_p param_structs) /* Nonzero if S is a type for which typed GC allocators should be output. */ #define USED_BY_TYPED_GC_P(s) \ - (((s->kind == TYPE_POINTER) \ - && ((s->u.p->gc_used == GC_POINTED_TO) \ - || (s->u.p->gc_used == GC_USED))) \ - || (UNION_OR_STRUCT_P (s) && \ - (((s)->gc_used == GC_POINTED_TO) \ - || ((s)->gc_used == GC_MAYBE_POINTED_TO \ - && s->u.s.line.file != NULL) \ - || ((s)->gc_used == GC_USED \ - && strncmp (s->u.s.tag, "anonymous", strlen ("anonymous")))))) + ((s->kind == TYPE_POINTER \ + && (s->u.p->gc_used == GC_POINTED_TO \ + || s->u.p->gc_used == GC_USED)) \ + || (union_or_struct_p (s) \ + && ((s)->gc_used == GC_POINTED_TO \ + || ((s)->gc_used == GC_MAYBE_POINTED_TO \ + && s->u.s.line.file != NULL) \ + || ((s)->gc_used == GC_USED \ + && strncmp (s->u.s.tag, "anonymous", strlen ("anonymous")))))) /* Write out the 'enum' definition for gt_types_enum. */ @@ -3619,7 +4003,7 @@ write_enum_defn (type_p structures, type_p param_structs) nbstruct++; DBGPRINTF ("write_enum_defn s @ %p nbstruct %d", (void*) s, nbstruct); - if (UNION_OR_STRUCT_P (s)) + if (union_or_struct_p (s)) DBGPRINTF ("write_enum_defn s %p #%d is unionorstruct tagged %s", (void*) s, nbstruct, s->u.s.tag); oprintf (header_file, " gt_ggc_e_"); @@ -3905,6 +4289,11 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length, } break; + case TYPE_USER_STRUCT: + write_root (f, v, type->u.a.p, name, has_length, line, if_marked, + emit_pch); + break; + case TYPE_POINTER: { type_p tp; @@ -3914,7 +4303,7 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length, tp = type->u.p; - if (!has_length && UNION_OR_STRUCT_P (tp)) + if (!has_length && union_or_struct_p (tp)) { const char *id_for_tag = filter_type_name (tp->u.s.tag); oprintf (f, " >_ggc_mx_%s,\n", id_for_tag); @@ -3938,7 +4327,7 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length, oprintf (f, ",\n NULL"); } else if (has_length - && (tp->kind == TYPE_POINTER || UNION_OR_STRUCT_P (tp))) + && (tp->kind == TYPE_POINTER || union_or_struct_p (tp))) { oprintf (f, " >_ggc_ma_%s,\n", name); if (emit_pch) @@ -4179,7 +4568,8 @@ write_roots (pair_p variables, bool emit_pch) continue; if (v->type->kind != TYPE_POINTER || v->type->u.p->kind != TYPE_PARAM_STRUCT - || v->type->u.p->u.param_struct.stru != find_structure ("htab", 0)) + || v->type->u.p->u.param_struct.stru != find_structure ("htab", + TYPE_STRUCT)) { error_at_line (&v->line, "if_marked option used but not hash table"); @@ -4282,77 +4672,6 @@ write_roots (pair_p variables, bool emit_pch) finish_root_table (flp, "pch_rs", "LAST_GGC_ROOT_TAB", "ggc_root_tab", "gt_pch_scalar_rtab"); } -/* Record the definition of the vec_prefix structure, as defined in vec.h: - - struct vec_prefix GTY(()) { - unsigned num; - unsigned alloc; - }; */ -static type_p -vec_prefix_type (void) -{ - static type_p prefix_type = NULL; - if (prefix_type == NULL) - { - pair_p fields; - static struct fileloc pos = { NULL, 0 }; - type_p len_ty = create_scalar_type ("unsigned"); - pos.file = input_file_by_name (__FILE__); pos.line = __LINE__; - fields = create_field_at (0, len_ty, "alloc", 0, &pos); - fields = create_field_at (fields, len_ty, "num", 0, &pos); - prefix_type = new_structure ("vec_prefix", 0, &pos, fields, 0); - prefix_type->u.s.bitmap = -1; - } - return prefix_type; -} - -/* Record the definition of a generic VEC structure, as if we had expanded - the macros in vec.h: - - typedef struct VEC__base GTY(()) { - struct vec_prefix prefix; - GTY((length ("%h.prefix.num"))) vec[1]; - } VEC__base - - where the GTY(()) tags are only present if is_scalar is _false_. */ - -void -note_def_vec (const char *type_name, bool is_scalar, struct fileloc *pos) -{ - pair_p fields; - type_p t; - options_p o; - const char *name = concat ("vec_t<", type_name, ">", (char *) 0); - - if (is_scalar) - { - t = create_scalar_type (type_name); - o = 0; - } - else - { - t = resolve_typedef (type_name, pos); - o = create_string_option (0, "length", "%h.prefix.num"); - } - /* We assemble the field list in reverse order. */ - fields = create_field_at (0, create_array (t, "1"), "vec", o, pos); - fields = create_field_at (fields, vec_prefix_type (), "prefix", 0, pos); - - do_typedef (name, new_structure (name, 0, pos, fields, 0), pos); -} - -/* Returns the specifier keyword for a string or union type S, empty string - otherwise. */ - -static const char * -get_type_specifier (const type_p s) -{ - if (s->kind == TYPE_STRUCT || s->kind == TYPE_LANG_STRUCT) - return "struct "; - if (s->kind == TYPE_UNION) - return "union "; - return ""; -} /* TRUE if type S has the GTY variable_size annotation. */ @@ -4421,7 +4740,7 @@ write_typed_struct_alloc_def (outf_p f, enum alloc_quantity quantity, enum alloc_zone zone) { - gcc_assert (UNION_OR_STRUCT_P (s)); + gcc_assert (union_or_struct_p (s)); write_typed_alloc_def (f, variable_size_p (s), get_type_specifier (s), s->u.s.tag, allocator_type, quantity, zone); } @@ -4456,7 +4775,7 @@ write_typed_alloc_defns (outf_p f, { if (!USED_BY_TYPED_GC_P (s)) continue; - gcc_assert (UNION_OR_STRUCT_P (s)); + gcc_assert (union_or_struct_p (s)); /* In plugin mode onput output ggc_alloc macro definitions relevant to plugin input files. */ if (nb_plugin_files > 0 @@ -4520,6 +4839,7 @@ output_typename (outf_p of, const_type_p t) output_typename (of, t->u.p); break; case TYPE_STRUCT: + case TYPE_USER_STRUCT: case TYPE_UNION: case TYPE_LANG_STRUCT: oprintf (of, "%s", t->u.s.tag); @@ -4578,10 +4898,6 @@ write_splay_tree_allocators (const_type_p param_structs) } } -static void dump_pair (int indent, pair_p p); -static void dump_type (int indent, type_p p); -static void dump_type_list (int indent, type_p p); - #define INDENT 2 /* Dumps the value of typekind KIND. */ @@ -4601,6 +4917,9 @@ dump_typekind (int indent, enum typekind kind) case TYPE_STRUCT: printf ("TYPE_STRUCT"); break; + case TYPE_USER_STRUCT: + printf ("TYPE_USER_STRUCT"); + break; case TYPE_UNION: printf ("TYPE_UNION"); break; @@ -4696,8 +5015,7 @@ dump_type_u_s (int indent, type_p t) { pair_p fields; - gcc_assert (t->kind == TYPE_STRUCT || t->kind == TYPE_UNION - || t->kind == TYPE_LANG_STRUCT); + gcc_assert (union_or_struct_p (t)); printf ("%*cu.s.tag = %s\n", indent, ' ', t->u.s.tag); dump_fileloc (indent, t->u.s.line); printf ("%*cu.s.fields =\n", indent, ' '); @@ -4768,6 +5086,9 @@ dump_type (int indent, type_p t) { PTR *slot; + if (seen_types == NULL) + seen_types = htab_create (100, htab_hash_pointer, htab_eq_pointer, NULL); + printf ("%*cType at %p: ", indent, ' ', (void *) t); slot = htab_find_slot (seen_types, t, INSERT); if (*slot != NULL) @@ -4793,6 +5114,7 @@ dump_type (int indent, type_p t) case TYPE_STRUCT: case TYPE_UNION: case TYPE_LANG_STRUCT: + case TYPE_USER_STRUCT: dump_type_u_s (indent + INDENT, t); break; case TYPE_POINTER: @@ -4852,11 +5174,12 @@ dump_structures (const char *name, type_p structures) static void dump_everything (void) { - seen_types = htab_create (100, htab_hash_pointer, htab_eq_pointer, NULL); dump_pair_list ("typedefs", typedefs); dump_structures ("structures", structures); dump_structures ("param_structs", param_structs); dump_pair_list ("variables", variables); + + /* Allocated with the first call to dump_type. */ htab_delete (seen_types); } diff --git a/gcc/gengtype.h b/gcc/gengtype.h index 1ff4e3f..2ca0e4e 100644 --- a/gcc/gengtype.h +++ b/gcc/gengtype.h @@ -1,5 +1,5 @@ /* Process source files and output type information. - Copyright (C) 2002, 2003, 2004, 2007, 2008, 2010, 2011 + Copyright (C) 2002, 2003, 2004, 2007, 2008, 2010, 2011, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -143,11 +143,14 @@ enum typekind { TYPE_LANG_STRUCT, /* GCC front-end language specific structs. Various languages may have homonymous but different structs. */ - TYPE_PARAM_STRUCT /* Type for parametrized structs, e.g. hash_t + TYPE_PARAM_STRUCT, /* Type for parametrized structs, e.g. hash_t hash-tables, ... See (param_is, use_param, param1_is, param2_is,... use_param1, use_param_2,... use_params) GTY options. */ + TYPE_USER_STRUCT /* User defined type. Walkers and markers for + this type are assumed to be provided by the + user. */ }; /* Discriminating kind for options. */ @@ -319,19 +322,27 @@ extern struct type scalar_char; /* Test if a type is a union, either a plain one or a language specific one. */ -#define UNION_P(x) \ - ((x)->kind == TYPE_UNION || \ - ((x)->kind == TYPE_LANG_STRUCT \ - && (x)->u.s.lang_struct->kind == TYPE_UNION)) +#define UNION_P(x) \ + ((x)->kind == TYPE_UNION \ + || ((x)->kind == TYPE_LANG_STRUCT \ + && (x)->u.s.lang_struct->kind == TYPE_UNION)) /* Test if a type is a union or a structure, perhaps a language specific one. */ -#define UNION_OR_STRUCT_P(x) \ - ((x)->kind == TYPE_UNION \ - || (x)->kind == TYPE_STRUCT \ - || (x)->kind == TYPE_LANG_STRUCT) - +static inline bool +union_or_struct_p (enum typekind kind) +{ + return (kind == TYPE_UNION + || kind == TYPE_STRUCT + || kind == TYPE_LANG_STRUCT + || kind == TYPE_USER_STRUCT); +} +static inline bool +union_or_struct_p (const_type_p x) +{ + return union_or_struct_p (x->kind); +} /* Give the file location of a type, if any. */ static inline struct fileloc* @@ -339,7 +350,7 @@ type_fileloc (type_p t) { if (!t) return NULL; - if (UNION_OR_STRUCT_P(t)) + if (union_or_struct_p (t)) return &t->u.s.line; if (t->kind == TYPE_PARAM_STRUCT) return &t->u.param_struct.line; @@ -410,10 +421,10 @@ extern char *xasprintf (const char *, ...) ATTRIBUTE_PRINTF_1; extern void do_typedef (const char *s, type_p t, struct fileloc *pos); extern void do_scalar_typedef (const char *s, struct fileloc *pos); extern type_p resolve_typedef (const char *s, struct fileloc *pos); -extern type_p new_structure (const char *name, int isunion, +extern type_p new_structure (const char *name, enum typekind kind, struct fileloc *pos, pair_p fields, options_p o); -extern type_p find_structure (const char *s, int isunion); +extern type_p find_structure (const char *s, enum typekind kind); extern type_p create_scalar_type (const char *name); extern type_p create_pointer (type_p t); extern type_p create_array (type_p t, const char *len); @@ -424,8 +435,6 @@ extern pair_p nreverse_pairs (pair_p list); extern type_p adjust_field_type (type_p, options_p); extern void note_variable (const char *s, type_p t, options_p o, struct fileloc *pos); -extern void note_def_vec (const char *type_name, bool is_scalar, - struct fileloc *pos); /* Lexer and parser routines. */ extern int yylex (const char **yylval); @@ -451,8 +460,6 @@ enum STRUCT, ENUM, VEC_TOKEN, - DEFVEC_OP, - DEFVEC_I, ELLIPSIS, PTR_ALIAS, NESTED_PTR, diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c index ff23092..15e5a67 100644 --- a/gcc/ggc-page.c +++ b/gcc/ggc-page.c @@ -1445,6 +1445,26 @@ gt_ggc_m_S (const void *p) return; } + +/* User-callable entry point for marking string X. */ + +void +gt_ggc_mx (const char *& x) +{ + gt_ggc_m_S (x); +} + +void +gt_ggc_mx (unsigned char *& x) +{ + gt_ggc_m_S (x); +} + +void +gt_ggc_mx (unsigned char& x ATTRIBUTE_UNUSED) +{ +} + /* If P is not marked, marks it and return false. Otherwise return true. P must have been allocated by the GC allocator; it mustn't point to static objects, stack variables, or memory allocated with malloc. */ diff --git a/gcc/ggc-zone.c b/gcc/ggc-zone.c index 5257ada..a422b5c 100644 --- a/gcc/ggc-zone.c +++ b/gcc/ggc-zone.c @@ -1517,6 +1517,21 @@ gt_ggc_m_S (const void *p) ggc_set_mark (p); } + +/* User-callable entry point for marking string X. */ + +void +gt_ggc_mx (const char *& x) +{ + gt_ggc_m_S (x); +} + +void +gt_ggc_mx (unsigned char *& x) +{ + gt_ggc_m_S (x); +} + /* If P is not marked, mark it and return false. Otherwise return true. P must have been allocated by the GC allocator; it mustn't point to static objects, stack variables, or memory allocated with malloc. */ diff --git a/gcc/stringpool.c b/gcc/stringpool.c index c567587..281e550 100644 --- a/gcc/stringpool.c +++ b/gcc/stringpool.c @@ -210,6 +210,32 @@ gt_pch_n_S (const void *x) gt_pch_note_object (CONST_CAST (void *, x), CONST_CAST (void *, x), >_pch_p_S, gt_types_enum_last); } + + +/* User-callable entry point for marking string X. */ + +void +gt_pch_nx (const char *& x) +{ + gt_pch_n_S (x); +} + +void +gt_pch_nx (unsigned char *& x) +{ + gt_pch_n_S (x); +} + +void +gt_pch_nx (unsigned char& x ATTRIBUTE_UNUSED) +{ +} + +void +gt_pch_nx (unsigned char *x, gt_pointer_operator op, void *cookie) +{ + op (x, cookie); +} /* Handle saving and restoring the string pool for PCH. */ diff --git a/gcc/vec.h b/gcc/vec.h index cc7e819..725e34d 100644 --- a/gcc/vec.h +++ b/gcc/vec.h @@ -156,7 +156,7 @@ extern void vec_assert_fail (const char *, const char * VEC_CHECK_DECL) enum vec_allocation_t { heap, gc, stack }; -struct GTY(()) vec_prefix +struct vec_prefix { unsigned num; unsigned alloc; @@ -167,9 +167,50 @@ template struct GTY(()) vec_t { vec_prefix prefix; - T GTY((length ("%h.prefix.num"))) vec[1]; + T vec[1]; }; +/* Garbage collection support for vec_t. */ + +template +void +gt_ggc_mx (vec_t *v) +{ + extern void gt_ggc_mx (T&); + for (unsigned i = 0; i < v->prefix.num; i++) + gt_ggc_mx (v->vec[i]); +} + + +/* PCH support for vec_t. */ + +template +void +gt_pch_nx (vec_t *v) +{ + extern void gt_pch_nx (T&); + for (unsigned i = 0; i < v->prefix.num; i++) + gt_pch_nx (v->vec[i]); +} + +template +void +gt_pch_nx (vec_t *v, gt_pointer_operator op, void *cookie) +{ + for (unsigned i = 0; i < v->prefix.num; i++) + op (&(v->vec[i]), cookie); +} + +template +void +gt_pch_nx (vec_t *v, gt_pointer_operator op, void *cookie) +{ + extern void gt_pch_nx (T *, gt_pointer_operator, void *); + for (unsigned i = 0; i < v->prefix.num; i++) + gt_pch_nx (&(v->vec[i]), op, cookie); +} + + /* FIXME cxx-conversion. Remove these definitions and update all calling sites. */ /* Vector of integer-like object. */