From patchwork Sun Aug 12 20:13:00 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Diego Novillo X-Patchwork-Id: 176799 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 4EF902C0087 for ; Mon, 13 Aug 2012 06:14:10 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1345407250; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:Received:Received:Received:Date:From:To:Cc:Subject: Message-ID:MIME-Version:Content-Type:Content-Disposition: User-Agent:Mailing-List:Precedence:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:Sender:Delivered-To; bh=C8iycVt i2w8AVOqAO1Ccp0x1bms=; b=o9fYX0TiCu2zsejjPTUMCakg3kEFk9i6k/gd60Y W1zYVYHQHtwLK5EnXsTTz5KKMaBWooAJTYViCfv+8JxKuhOcwM0l2PmnT1yflh5U LgLtNscUBjQK/o4DIGJQH3xE0dtUvhoc/08q3ScMmXvCPeRAsTpujr7Pv+aCETH4 lLsw= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:X-Google-DKIM-Signature:Received:Received:Received:Received:Received:Date:From:To:Cc:Subject:Message-ID:MIME-Version:Content-Type:Content-Disposition:User-Agent:X-Gm-Message-State:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=pnSH7/C7Yljps4P0JxLTQOAEbsg5W6JDtd4CNnAeR5Dud5D3kQI85Q+MkdhDFr bpGh7U476vFSeEoLZKYU3L1NMCyaCJkXKdIL/loQjs6SP0hOHt35y1Gt/1/9GNnp paWW+HGU3NQyGfBsXMxJp0rMgYMR7ydVbJuYg2/sMCC/g=; Received: (qmail 25832 invoked by alias); 12 Aug 2012 20:14:03 -0000 Received: (qmail 25760 invoked by uid 22791); 12 Aug 2012 20:13:44 -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; Sun, 12 Aug 2012 20:13:02 +0000 Received: by obbun3 with SMTP id un3so2202784obb.2 for ; Sun, 12 Aug 2012 13:13:02 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=date:from:to:cc:subject:message-id:mime-version:content-type :content-disposition:organization:user-agent:x-gm-message-state; bh=MjC322MV2CJfpV4IHJfazTR4Ilg481OxO9FZRV+0J+c=; b=guf7PTLWzCaG5/pi60dN9+Vn54PksTLvVJcsz3RQfUaKxRAqx2O1i7HAIHT8c11Z7+ spvNoUzB9pH41RawNu7yidlNfLsBQ7Xe+JdOyj9hs7FsNNeIsYZk9do/lgZw6Lyi1DBM EtIaBBCI0luMbylubwW7mpXoVcJ0JoKcxO40CblU5Lf7eGyjVLpT3TA5q9y2smtdKnIe LZhNjH5stU6nKp5/xrjiSMhWy9CLi5uJYSJ+UJHiBrmq+MqDmd6XBwqlxqNqcqkoqWMs XOJJRwmGKD5ILz8lWvuFA0s+bZ5nq+k8oD+xAEuuk1c6IDz7AtBOomciS3Z87eWP7EDa UhBw== Received: by 10.42.57.79 with SMTP id c15mr2388271ich.33.1344802381729; Sun, 12 Aug 2012 13:13:01 -0700 (PDT) Received: by 10.42.57.79 with SMTP id c15mr2388264ich.33.1344802381669; Sun, 12 Aug 2012 13:13:01 -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 ad4si1545859igc.1.2012.08.12.13.13.01 (version=TLSv1/SSLv3 cipher=AES128-SHA); Sun, 12 Aug 2012 13:13:01 -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 0879C100047; Sun, 12 Aug 2012 13:13:01 -0700 (PDT) Received: by torture.tor.corp.google.com (Postfix, from userid 54752) id A0DCBC0D36; Sun, 12 Aug 2012 16:13:00 -0400 (EDT) Date: Sun, 12 Aug 2012 16:13:00 -0400 From: Diego Novillo To: gcc-patches@gcc.gnu.org Cc: Laurynas Biveinis , tromey@redhat.com Subject: Merge C++ conversion into trunk (3/6 - gengtype C++ support) Message-ID: <20120812201300.GA14743@google.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-Gm-Message-State: ALoCoQlVbgV4vIC8ta7JI/Jyy/OZQMD1j05aAnWRs2L7kzEHclS9L+tA9fjyprQN3QddxNMBxFxSk2s1bsWLP/sJ7bEqkmlaqYe7Ulx5YtCU+EMGAXbbzIhIfjMmNQmoDnaoj7D4yYl5vjrv5el7oWjfPcGTIGb5UXM1+Z04sC8+c3nv50ofQpPGHwbtCUHiKtyEroivePMEVWJ7+WvAdm2VqzCLvAZsNvuEewmrIYp150BVwtprmPI= X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This merges the changes needed for supporting C++ types in gengtype. See http://gcc.gnu.org/ml/gcc-patches/2012-08/msg00711.html for details. Diego. 2012-08-12 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. * basic-block.h (struct edge_def): Mark GTY((user)). Remove all GTY markers from fields. (gt_ggc_mx): Declare. (gt_pch_nx): Declare. * tree-cfg.c (gt_ggc_mx): New. (gt_pch_nx): New. * gengtype-lex.l (USER_GTY): Add pattern for "user". * gengtype-parse.c (option): Handle USER_GTY. (opts_have): New. (type): Call it. If the keyword 'user' is used, do not walk the fields of the structure. * gengtype.h (USER_GTY): Add. * doc/gty.texi: Update. diff --git a/gcc/basic-block.h b/gcc/basic-block.h index dff06e4..7d1ad4f 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -33,19 +33,19 @@ along with GCC; see the file COPYING3. If not see typedef HOST_WIDEST_INT gcov_type; /* Control flow edge information. */ -struct GTY(()) edge_def { +struct GTY((user)) edge_def { /* The two blocks at the ends of the edge. */ basic_block src; basic_block dest; /* Instructions queued on the edge. */ union edge_def_insns { - gimple_seq GTY ((tag ("true"))) g; - rtx GTY ((tag ("false"))) r; - } GTY ((desc ("current_ir_type () == IR_GIMPLE"))) insns; + gimple_seq g; + rtx r; + } insns; /* Auxiliary info specific to a pass. */ - PTR GTY ((skip (""))) aux; + PTR aux; /* Location of any goto implicit in the edge and associated BLOCK. */ tree goto_block; @@ -65,6 +65,11 @@ DEF_VEC_P(edge); DEF_VEC_ALLOC_P(edge,gc); DEF_VEC_ALLOC_P(edge,heap); +/* Garbage collection and PCH support for edge_def. */ +extern void gt_ggc_mx (edge_def *e); +extern void gt_pch_nx (edge_def *e); +extern void gt_pch_nx (edge_def *e, gt_pointer_operator, void *); + /* Masks for edge.flags. */ #define DEF_EDGE_FLAG(NAME,IDX) EDGE_##NAME = 1 << IDX , enum cfg_edge_flags { 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/doc/gty.texi b/gcc/doc/gty.texi index ad0423a..3754b75 100644 --- a/gcc/doc/gty.texi +++ b/gcc/doc/gty.texi @@ -68,6 +68,7 @@ These don't need to be marked. @menu * GTY Options:: What goes inside a @code{GTY(())}. * GGC Roots:: Making global variables GGC roots. +* User GC:: Adding user-provided GC marking routines. * Files:: How the generated files work. * Invoking the garbage collector:: How to invoke the garbage collector. * Troubleshooting:: When something does not work as expected. @@ -440,8 +441,128 @@ The @code{special} option is used to mark types that have to be dealt with by special case machinery. The parameter is the name of the special case. See @file{gengtype.c} for further details. Avoid adding new special cases unless there is no other alternative. + +@findex user +@item user + +The @code{user} option indicates that the code to mark structure +fields is completely handled by user-provided routines. Section +@ref{User GC} for details on what functions need to be provided. @end table +@node User GC +@section Support for user-provided GC marking routines +@cindex user gc +The garbage collector supports types for which no automatic marking +code is generated. For these types, the user is required to provide +three functions: one to act as a marker for garbage collection, and +two functions to act as marker and pointer walking for pre-compiled +headers. + +Given a structure @code{struct GTY((user)) my_struct}, the following functions +should be defined to mark @code{my_struct}: + +@smallexample +void gt_ggc_mx (my_struct *p) +@{ + /* This marks field 'fld'. */ + gt_ggc_mx (p->fld); +@} + +void gt_pch_nx (my_struct *p) +@{ + /* This marks field 'fld'. */ + gt_pch_nx (tp->fld); +@} + +void gt_pch_nx (my_struct *p, gt_pointer_operator op, void *cookie) +@{ + /* For every field 'fld', call the given pointer operator. */ + op (&(tp->fld), cookie); +@} +@end smallexample + +In general, each marker @code{M} should call @code{M} for every +pointer field in the structure. Fields that are not allocated in GC +or are not pointers can be ignored. + +For embedded lists (e.g., structures with a @code{next} or @code{prev} +pointer), the marker must follow the chain and mark every element in +it. + +Note that the rules for the pointer walker @code{gt_pch_nx (my_struct +*, gt_pointer_operator, void *)} are slightly different. In this +case, the operation @code{op} must be applied to the @emph{address} of +every pointer field. + +@section User-provided marking routines for template types +When a template type @code{TP} is marked with @code{GTY}, all +instances of that type are considered user-provided types. This means +that the individual instances of @code{TP} do not need to marked with +@code{GTY}. 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). +@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 a71cce0..5788a6a 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,19 +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; -} -^{HWS}DEF_VEC_ALLOC_[IOP]/{EOID} { - BEGIN(in_struct); - return DEFVEC_ALLOC; -} } { @@ -121,6 +108,7 @@ EOID [^[:alnum:]_] "enum"/{EOID} { return ENUM; } "ptr_alias"/{EOID} { return PTR_ALIAS; } "nested_ptr"/{EOID} { return NESTED_PTR; } +"user"/{EOID} { return USER_GTY; } [0-9]+ { return NUM; } "param"[0-9]*"_is"/{EOID} { *yylval = XDUPVAR (const char, yytext, yyleng, yyleng+1); diff --git a/gcc/gengtype-parse.c b/gcc/gengtype-parse.c index c0ad403..03ee781 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,9 +77,6 @@ static const char *const token_names[] = { "struct", "enum", "VEC", - "DEF_VEC_[OP]", - "DEF_VEC_I", - "DEF_VEC_ALLOC_[IOP]", "...", "ptr_alias", "nested_ptr", @@ -212,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_", c1, "_", c2, (char *) 0); + 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 ()[]{}. */ @@ -460,6 +499,10 @@ option (options_p prev) advance (); return nestedptr_optvalue (prev); + case USER_GTY: + advance (); + return create_string_option (prev, "user", ""); + default: parse_error ("expected an option keyword, have %s", print_cur_token ()); advance (); @@ -694,6 +737,18 @@ struct_field_seq (void) return nreverse_pairs (f); } +/* Return true if OPTS contain the option named STR. */ + +static bool +opts_have (options_p opts, const char *str) +{ + for (options_p opt = opts; opt; opt = opt->next) + if (strcmp (opt->name, str) == 0) + return true; + return false; +} + + /* This is called type(), but what it parses (sort of) is what C calls declaration-specifiers and specifier-qualifier-list: @@ -735,7 +790,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(()) @@ -766,6 +821,7 @@ type (options_p *optsp, bool nested) if (is_gty) { + bool is_user_gty = opts_have (opts, "user"); if (token () == '{') { pair_p fields; @@ -773,17 +829,28 @@ type (options_p *optsp, bool nested) if (is_gty == GTY_AFTER_ID) parse_error ("GTY must be specified before identifier"); - advance (); - fields = struct_field_seq (); - require ('}'); - return new_structure (s, is_union, &lexer_line, fields, opts); + if (!is_user_gty) + { + advance (); + fields = struct_field_seq (); + require ('}'); + } + else + { + /* Do not look inside user defined structures. */ + fields = NULL; + kind = TYPE_USER_STRUCT; + consume_balanced ('{', '}'); + } + + 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: @@ -891,55 +958,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); - note_def_vec_alloc (type, "none", &lexer_line); -} - -/* Definition of an allocation strategy for a VEC structure: - - 'DEF_VEC_ALLOC_[IPO]' '(' id ',' id ')' ';' - - For purposes of gengtype, this just declares a wrapper structure. */ -static void -def_vec_alloc (void) -{ - const char *type, *astrat; - - require (DEFVEC_ALLOC); - require ('('); - type = require2 (ID, SCALAR); - require (','); - astrat = require (ID); - require (')'); - require (';'); - - if (!type || !astrat) - return; - - note_def_vec_alloc (type, astrat, &lexer_line); -} - /* Parse the file FNAME for GC-relevant declarations and definitions. This is the only entry point to this file. */ void @@ -964,15 +982,6 @@ parse_file (const char *fname) typedef_decl (); break; - case DEFVEC_OP: - case DEFVEC_I: - def_vec (); - break; - - case DEFVEC_ALLOC: - def_vec_alloc (); - 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 a4aa725..a3b0c2b 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 +90,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 +171,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 +187,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 +220,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 +550,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 +603,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 +686,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 +698,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 +720,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 +920,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 +1062,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 +1111,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 +1121,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 +1254,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 +1270,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 +1300,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 @@ -1275,8 +1347,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", @@ -1369,6 +1441,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; @@ -1468,7 +1541,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", @@ -2176,7 +2249,6 @@ close_output_files (void) for (of = output_files; of; of = of->next) { - if (!is_file_equal (of)) { FILE *newfile = NULL; @@ -2303,9 +2375,38 @@ struct walk_type_data bool fn_wants_lvalue; bool in_record_p; int loopcounter; + bool in_ptr_field; bool have_this_obj; }; + +/* Given a string TYPE_NAME, representing a C++ typename, return a valid + pre-processor identifier to use in a #define directive. This replaces + special characters used in C++ identifiers like '>', '<' and ':' with + '_'. + + If no C++ special characters are found in TYPE_NAME, return + TYPE_NAME. Otherwise, return a copy of TYPE_NAME with the special + characters replaced with '_'. In this case, the caller is + responsible for freeing the allocated string. */ + +static const char * +filter_type_name (const char *type_name) +{ + if (strchr (type_name, '<') || strchr (type_name, ':')) + { + size_t i; + char *s = xstrdup (type_name); + for (i = 0; i < strlen (s); i++) + if (s[i] == '<' || s[i] == '>' || s[i] == ':') + s[i] = '_'; + return s; + } + else + return type_name; +} + + /* Print a mangled name representing T to OF. */ static void @@ -2332,8 +2433,14 @@ output_mangled_typename (outf_p of, const_type_p t) case TYPE_STRUCT: case TYPE_UNION: case TYPE_LANG_STRUCT: - oprintf (of, "%lu%s", (unsigned long) strlen (t->u.s.tag), - t->u.s.tag); + 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), + id_for_tag); + if (id_for_tag != t->u.s.tag) + free (CONST_CAST(char *, id_for_tag)); + } break; case TYPE_PARAM_STRUCT: { @@ -2390,6 +2497,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 @@ -2470,7 +2578,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); @@ -2498,7 +2606,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", @@ -2521,6 +2629,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); @@ -2548,7 +2657,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, @@ -2561,7 +2670,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 " @@ -2638,6 +2747,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; @@ -2921,6 +3031,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 (); } @@ -2978,7 +3092,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); @@ -2998,13 +3112,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: @@ -3025,7 +3153,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); @@ -3043,13 +3171,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 @@ -3057,13 +3185,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, @@ -3113,22 +3413,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) - 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); - } + 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); @@ -3211,9 +3508,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) { @@ -3226,8 +3531,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 @@ -3238,23 +3547,27 @@ 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) { options_p opt; + const char *s_id_for_tag; if (s->gc_used == GC_MAYBE_POINTED_TO && s->u.s.line.file == NULL) continue; + s_id_for_tag = filter_type_name (s->u.s.tag); + oprintf (output_header, "#define gt_%s_", wtd->prefix); output_mangled_typename (output_header, s); oprintf (output_header, "(X) do { \\\n"); oprintf (output_header, " if (X != NULL) gt_%sx_%s (X);\\\n", wtd->prefix, - s->u.s.tag); + s_id_for_tag); oprintf (output_header, " } while (0)\n"); for (opt = s->u.s.opt; opt; opt = opt->next) @@ -3264,9 +3577,14 @@ write_types (outf_p output_header, type_p structures, type_p param_structs, const_type_p const t = (const_type_p) opt->info.type; if (t->kind == TYPE_STRUCT || t->kind == TYPE_UNION || t->kind == TYPE_LANG_STRUCT) - oprintf (output_header, - "#define gt_%sx_%s gt_%sx_%s\n", - wtd->prefix, s->u.s.tag, wtd->prefix, t->u.s.tag); + { + const char *t_id_for_tag = filter_type_name (t->u.s.tag); + oprintf (output_header, + "#define gt_%sx_%s gt_%sx_%s\n", + wtd->prefix, s->u.s.tag, wtd->prefix, t_id_for_tag); + if (t_id_for_tag != t->u.s.tag) + free (CONST_CAST(char *, t_id_for_tag)); + } else error_at_line (&s->u.s.line, "structure alias is not a structure"); @@ -3278,7 +3596,10 @@ write_types (outf_p output_header, type_p structures, type_p param_structs, /* Declare the marker procedure only once. */ oprintf (output_header, "extern void gt_%sx_%s (void *);\n", - wtd->prefix, s->u.s.tag); + wtd->prefix, s_id_for_tag); + + if (s_id_for_tag != s->u.s.tag) + free (CONST_CAST(char *, s_id_for_tag)); if (s->u.s.line.file == NULL) { @@ -3400,6 +3721,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 @@ -3419,6 +3824,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; @@ -3427,6 +3842,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 @@ -3460,13 +3876,29 @@ 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; d.have_this_obj = true; - 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. */ @@ -3478,6 +3910,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) @@ -3557,15 +3990,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. */ @@ -3587,7 +4020,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_"); @@ -3873,6 +4306,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; @@ -3882,13 +4320,16 @@ 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)) { - oprintf (f, " >_ggc_mx_%s,\n", tp->u.s.tag); + const char *id_for_tag = filter_type_name (tp->u.s.tag); + oprintf (f, " >_ggc_mx_%s,\n", id_for_tag); if (emit_pch) - oprintf (f, " >_pch_nx_%s", tp->u.s.tag); + oprintf (f, " >_pch_nx_%s", id_for_tag); else oprintf (f, " NULL"); + if (id_for_tag != tp->u.s.tag) + free (CONST_CAST(char *, id_for_tag)); } else if (!has_length && tp->kind == TYPE_PARAM_STRUCT) { @@ -3903,7 +4344,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) @@ -4146,7 +4587,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"); @@ -4249,96 +4691,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_", type_name, "_base", (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); -} - -/* Record the definition of an allocation-specific VEC structure, as if - we had expanded the macros in vec.h: - - typedef struct VEC__ { - VEC__base base; - } VEC__; -*/ -void -note_def_vec_alloc (const char *type, const char *astrat, struct fileloc *pos) -{ - const char *astratname = concat ("VEC_", type, "_", astrat, (char *) 0); - const char *basename = concat ("VEC_", type, "_base", (char *) 0); - - pair_p field = create_field_at (0, resolve_typedef (basename, pos), - "base", 0, pos); - - do_typedef (astratname, new_structure (astratname, 0, pos, field, 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. */ @@ -4374,8 +4726,10 @@ write_typed_alloc_def (outf_p f, bool two_args = variable_size && (quantity == vector); bool third_arg = ((zone == specific_zone) && (variable_size || (quantity == vector))); + const char *type_name_as_id; gcc_assert (f != NULL); - oprintf (f, "#define ggc_alloc_%s%s", allocator_type, type_name); + type_name_as_id = filter_type_name (type_name); + oprintf (f, "#define ggc_alloc_%s%s", allocator_type, type_name_as_id); oprintf (f, "(%s%s%s%s%s) ", (variable_size ? "SIZE" : ""), (two_args ? ", " : ""), @@ -4392,6 +4746,8 @@ write_typed_alloc_def (outf_p f, if (quantity == vector) oprintf (f, ", n"); oprintf (f, " MEM_STAT_INFO)))\n"); + if (type_name_as_id != type_name) + free (CONST_CAST(char *, type_name_as_id)); } /* Writes a typed allocator definition into output F for a struct or @@ -4403,7 +4759,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); } @@ -4438,7 +4794,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 @@ -4502,6 +4858,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); @@ -4560,10 +4917,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. */ @@ -4583,6 +4936,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; @@ -4678,8 +5034,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, ' '); @@ -4750,6 +5105,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) @@ -4775,6 +5133,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: @@ -4834,11 +5193,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 560f7f3..4a178ec 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,10 +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); -extern void note_def_vec_alloc (const char *type, const char *astrat, - struct fileloc *pos); /* Lexer and parser routines. */ extern int yylex (const char **yylval); @@ -453,12 +460,10 @@ enum STRUCT, ENUM, VEC_TOKEN, - DEFVEC_OP, - DEFVEC_I, - DEFVEC_ALLOC, ELLIPSIS, PTR_ALIAS, NESTED_PTR, + USER_GTY, PARAM_IS, NUM, SCALAR, diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c index d3d186d..f43d0c2 100644 --- a/gcc/ggc-page.c +++ b/gcc/ggc-page.c @@ -1441,6 +1441,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 baf8076..3fe0dd2 100644 --- a/gcc/ggc-zone.c +++ b/gcc/ggc-zone.c @@ -1508,6 +1508,26 @@ 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); +} + +void +gt_ggc_mx (unsigned char& x ATTRIBUTE_UNUSED) +{ +} + /* 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/ggc.h b/gcc/ggc.h index 59a996b..5f25a58 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/stringpool.c b/gcc/stringpool.c index 747db17..281e550 100644 --- a/gcc/stringpool.c +++ b/gcc/stringpool.c @@ -49,7 +49,7 @@ static const char digit_vector[] = { struct ht *ident_hash; -static hashnode alloc_node (hash_table *); +static hashnode alloc_node (cpp_hash_table *); static int mark_ident (struct cpp_reader *, hashnode, const void *); static void * @@ -70,7 +70,7 @@ init_stringpool (void) /* Allocate a hash node. */ static hashnode -alloc_node (hash_table *table ATTRIBUTE_UNUSED) +alloc_node (cpp_hash_table *table ATTRIBUTE_UNUSED) { return GCC_IDENT_TO_HT_IDENT (make_node (IDENTIFIER_NODE)); } @@ -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/tree-cfg.c b/gcc/tree-cfg.c index a91b433..c88a9f9 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -7863,3 +7863,54 @@ struct gimple_opt_pass pass_warn_unused_result = 0, /* todo_flags_finish */ } }; + + +/* Garbage collection support for edge_def. */ + +extern void gt_ggc_mx (tree&); +extern void gt_ggc_mx (gimple&); +extern void gt_ggc_mx (rtx&); +extern void gt_ggc_mx (basic_block&); + +void +gt_ggc_mx (edge_def *e) +{ + gt_ggc_mx (e->src); + gt_ggc_mx (e->dest); + if (current_ir_type () == IR_GIMPLE) + gt_ggc_mx (e->insns.g); + else + gt_ggc_mx (e->insns.r); + gt_ggc_mx (e->goto_block); +} + +/* PCH support for edge_def. */ + +extern void gt_pch_nx (tree&); +extern void gt_pch_nx (gimple&); +extern void gt_pch_nx (rtx&); +extern void gt_pch_nx (basic_block&); + +void +gt_pch_nx (edge_def *e) +{ + gt_pch_nx (e->src); + gt_pch_nx (e->dest); + if (current_ir_type () == IR_GIMPLE) + gt_pch_nx (e->insns.g); + else + gt_pch_nx (e->insns.r); + gt_pch_nx (e->goto_block); +} + +void +gt_pch_nx (edge_def *e, gt_pointer_operator op, void *cookie) +{ + op (&(e->src), cookie); + op (&(e->dest), cookie); + if (current_ir_type () == IR_GIMPLE) + op (&(e->insns.g), cookie); + else + op (&(e->insns.r), cookie); + op (&(e->goto_block), cookie); +}