From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 17028 invoked by alias); 16 May 2014 15:26:58 -0000 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 Received: (qmail 16953 invoked by uid 89); 16 May 2014 15:26:58 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.1 required=5.0 tests=AWL,BAYES_00,KAM_STOCKGEN autolearn=no version=3.3.2 X-HELO: eggs.gnu.org Received: from eggs.gnu.org (HELO eggs.gnu.org) (208.118.235.92) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Fri, 16 May 2014 15:26:55 +0000 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WlK22-0004WV-C1 for gcc-patches@gcc.gnu.org; Fri, 16 May 2014 11:26:53 -0400 Received: from mx1.redhat.com ([209.132.183.28]:3515) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WlK22-0004Vc-3u for gcc-patches@gcc.gnu.org; Fri, 16 May 2014 11:26:46 -0400 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s4GFQjDY003788 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Fri, 16 May 2014 11:26:45 -0400 Received: from barimba.redhat.com (ovpn-113-182.phx2.redhat.com [10.3.113.182]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s4GFQhHT022960; Fri, 16 May 2014 11:26:44 -0400 From: Tom Tromey To: gcc-patches@gcc.gnu.org Cc: Tom Tromey Subject: [PATCH 3/5] introduce the binding oracle Date: Fri, 16 May 2014 15:27:00 -0000 Message-Id: <1400254001-12038-4-git-send-email-tromey@redhat.com> In-Reply-To: <1400254001-12038-1-git-send-email-tromey@redhat.com> References: <1400254001-12038-1-git-send-email-tromey@redhat.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 X-SW-Source: 2014-05/txt/msg01289.txt.bz2 gdb wants to supply any declarations that may be referred to by the user's code. Hooking into symbol lookup was an efficient way to accomplish this. This patch introducing a "binding oracle" that is consulted whenever a symbol binding is looked up for the first time. The oracle is just a global function pointer. If it is NULL, no special work is done. It is called with the identifier to supply and with an enum argument indicating the kind of binding being requested. The oracle can then call back into the C front end (via the new functions c_pushtag and c_bind) to supply a binding; or it can silently do nothing if the request could not be fulfilled. The code caches Whether the oracle has been called to avoid repeated useless queries. There is a little hack in c_print_identifier to avoid calling the binding oracle here. This makes debugging gcc in the presence of the plugin remain relatively sane -- without this, calling debug_tree or the like can confusingly call into the plugin. 2014-05-16 Phil Muldoon Tom Tromey * c-tree.h (enum c_oracle_request): New. (c_binding_oracle_function): New typedef. (c_binding_oracle, c_pushtag, c_bind): Declare. * c-decl.c (c_binding_oracle): New global. (I_SYMBOL_CHECKED): New macro. (i_symbol_binding): New function. (I_SYMBOL_BINDING, I_SYMBOL_DECL): Redefine. (I_TAG_CHECKED): New macro. (i_tag_binding): New function. (I_TAG_BINDING, I_TAG_DECL): Redefine. (I_LABEL_CHECKED): New macro. (i_label_binding): New function. (I_LABEL_BINDING, I_LABEL_DECL): Redefine. (c_print_identifier): Save and restore c_binding_oracle. (c_pushtag, c_bind): New functions. --- gcc/c/ChangeLog | 19 +++++++ gcc/c/c-decl.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++------ gcc/c/c-tree.h | 24 +++++++++ 3 files changed, 189 insertions(+), 15 deletions(-) diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index d52dcc9..b391add 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -215,21 +215,6 @@ struct GTY((chain_next ("%h.prev"))) c_binding { #define B_IN_FILE_SCOPE(b) ((b)->depth == 1 /*file_scope->depth*/) #define B_IN_EXTERNAL_SCOPE(b) ((b)->depth == 0 /*external_scope->depth*/) -#define I_SYMBOL_BINDING(node) \ - (((struct lang_identifier *) IDENTIFIER_NODE_CHECK(node))->symbol_binding) -#define I_SYMBOL_DECL(node) \ - (I_SYMBOL_BINDING(node) ? I_SYMBOL_BINDING(node)->decl : 0) - -#define I_TAG_BINDING(node) \ - (((struct lang_identifier *) IDENTIFIER_NODE_CHECK(node))->tag_binding) -#define I_TAG_DECL(node) \ - (I_TAG_BINDING(node) ? I_TAG_BINDING(node)->decl : 0) - -#define I_LABEL_BINDING(node) \ - (((struct lang_identifier *) IDENTIFIER_NODE_CHECK(node))->label_binding) -#define I_LABEL_DECL(node) \ - (I_LABEL_BINDING(node) ? I_LABEL_BINDING(node)->decl : 0) - /* Each C symbol points to three linked lists of c_binding structures. These describe the values of the identifier in the three different namespaces defined by the language. */ @@ -245,6 +230,96 @@ struct GTY(()) lang_identifier { extern char C_SIZEOF_STRUCT_LANG_IDENTIFIER_isnt_accurate [(sizeof(struct lang_identifier) == C_SIZEOF_STRUCT_LANG_IDENTIFIER) ? 1 : -1]; +/* The binding oracle; see c-tree.h. */ +void (*c_binding_oracle) (enum c_oracle_request, tree identifier); + +/* This flag is set on an identifier if we have previously asked the + binding oracle for this identifier's symbol binding. */ +#define I_SYMBOL_CHECKED(node) \ + (TREE_LANG_FLAG_4 (IDENTIFIER_NODE_CHECK (node))) + +static inline struct c_binding* * +i_symbol_binding (tree node) +{ + struct lang_identifier *lid + = (struct lang_identifier *) IDENTIFIER_NODE_CHECK (node); + + if (lid->symbol_binding == NULL + && c_binding_oracle != NULL + && !I_SYMBOL_CHECKED (node)) + { + /* Set the "checked" flag first, to avoid infinite recursion + when the binding oracle calls back into gcc. */ + I_SYMBOL_CHECKED (node) = 1; + c_binding_oracle (C_ORACLE_SYMBOL, node); + } + + return &lid->symbol_binding; +} + +#define I_SYMBOL_BINDING(node) (*i_symbol_binding (node)) + +#define I_SYMBOL_DECL(node) \ + (I_SYMBOL_BINDING(node) ? I_SYMBOL_BINDING(node)->decl : 0) + +/* This flag is set on an identifier if we have previously asked the + binding oracle for this identifier's tag binding. */ +#define I_TAG_CHECKED(node) \ + (TREE_LANG_FLAG_5 (IDENTIFIER_NODE_CHECK (node))) + +static inline struct c_binding ** +i_tag_binding (tree node) +{ + struct lang_identifier *lid + = (struct lang_identifier *) IDENTIFIER_NODE_CHECK (node); + + if (lid->tag_binding == NULL + && c_binding_oracle != NULL + && !I_TAG_CHECKED (node)) + { + /* Set the "checked" flag first, to avoid infinite recursion + when the binding oracle calls back into gcc. */ + I_TAG_CHECKED (node) = 1; + c_binding_oracle (C_ORACLE_TAG, node); + } + + return &lid->tag_binding; +} + +#define I_TAG_BINDING(node) (*i_tag_binding (node)) + +#define I_TAG_DECL(node) \ + (I_TAG_BINDING(node) ? I_TAG_BINDING(node)->decl : 0) + +/* This flag is set on an identifier if we have previously asked the + binding oracle for this identifier's label binding. */ +#define I_LABEL_CHECKED(node) \ + (TREE_LANG_FLAG_6 (IDENTIFIER_NODE_CHECK (node))) + +static inline struct c_binding ** +i_label_binding (tree node) +{ + struct lang_identifier *lid + = (struct lang_identifier *) IDENTIFIER_NODE_CHECK (node); + + if (lid->label_binding == NULL + && c_binding_oracle != NULL + && !I_LABEL_CHECKED (node)) + { + /* Set the "checked" flag first, to avoid infinite recursion + when the binding oracle calls back into gcc. */ + I_LABEL_CHECKED (node) = 1; + c_binding_oracle (C_ORACLE_LABEL, node); + } + + return &lid->label_binding; +} + +#define I_LABEL_BINDING(node) (*i_label_binding (node)) + +#define I_LABEL_DECL(node) \ + (I_LABEL_BINDING(node) ? I_LABEL_BINDING(node)->decl : 0) + /* The resulting tree type. */ union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"), @@ -611,6 +686,12 @@ decl_jump_unsafe (tree decl) void c_print_identifier (FILE *file, tree node, int indent) { + void (*save) (enum c_oracle_request, tree identifier); + + // This makes debugging much more sane. + save = c_binding_oracle; + c_binding_oracle = NULL; + print_node (file, "symbol", I_SYMBOL_DECL (node), indent + 4); print_node (file, "tag", I_TAG_DECL (node), indent + 4); print_node (file, "label", I_LABEL_DECL (node), indent + 4); @@ -621,6 +702,8 @@ c_print_identifier (FILE *file, tree node, int indent) fprintf (file, "rid " HOST_PTR_PRINTF " \"%s\"", (void *) rid, IDENTIFIER_POINTER (rid)); } + + c_binding_oracle = save; } /* Establish a binding between NAME, an IDENTIFIER_NODE, and DECL, @@ -1485,6 +1568,54 @@ pushtag (location_t loc, tree name, tree type) } } } + +/* An exported interface to pushtag. This is used by the gdb plugin's + binding oracle to introduce a new tag binding. */ + +void +c_pushtag (location_t loc, tree name, tree type) +{ + pushtag (loc, name, type); +} + +/* An exported interface to bind a declaration. LOC is the location + to use. DECL is the declaration to bind. The decl's name is used + to determine how it is bound. If DECL is a VAR_DECL, then + IS_GLOBAL determines whether the decl is put into the global (file + and external) scope or the current function's scope; if DECL is not + a VAR_DECL then it is always put into the file scope. */ + +void +c_bind (location_t loc, tree decl, bool is_global) +{ + struct c_scope *scope; + bool nested = false; + + if (TREE_CODE (decl) != VAR_DECL || current_function_scope == NULL) + { + /* Types and functions are always considered to be global. */ + scope = file_scope; + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + } + else if (is_global) + { + /* Also bind it into the external scope. */ + bind (DECL_NAME (decl), decl, external_scope, true, false, loc); + nested = true; + scope = file_scope; + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + } + else + { + DECL_CONTEXT (decl) = current_function_decl; + TREE_PUBLIC (decl) = 0; + scope = current_function_scope; + } + + bind (DECL_NAME (decl), decl, scope, false, nested, loc); +} /* Subroutine of compare_decls. Allow harmless mismatches in return and argument types provided that the type modes match. This function diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index e7dcb35..9370fa6 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -665,12 +665,36 @@ extern int current_function_returns_abnormally; extern enum machine_mode c_default_pointer_mode; /* In c-decl.c */ + +/* Tell the binding oracle what kind of binding we are looking for. */ + +enum c_oracle_request +{ + C_ORACLE_SYMBOL, + C_ORACLE_TAG, + C_ORACLE_LABEL +}; + +/* If this is non-NULL, then it is a "binding oracle" which can lazily + create bindings when needed by the C compiler. The oracle is told + the name and type of the binding to create. It can call pushdecl + or the like to ensure the binding is visible; or do nothing, + leaving the binding untouched. c-decl.c takes note of when the + oracle has been called and will not call it again if it fails to + create a given binding. */ + +typedef void c_binding_oracle_function (enum c_oracle_request, tree identifier); + +extern c_binding_oracle_function *c_binding_oracle; + extern void c_finish_incomplete_decl (tree); extern void c_write_global_declarations (void); extern tree c_omp_reduction_id (enum tree_code, tree); extern tree c_omp_reduction_decl (tree); extern tree c_omp_reduction_lookup (tree, tree); extern tree c_check_omp_declare_reduction_r (tree *, int *, void *); +extern void c_pushtag (location_t, tree, tree); +extern void c_bind (location_t, tree, bool); /* In c-errors.c */ extern void pedwarn_c90 (location_t, int opt, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); -- 1.9.0