📄 search.c
字号:
/* Breadth-first and depth-first routines for searching multiple-inheritance lattice for GNU C++. Copyright (C) 1987, 89, 92-96, 1997 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com)This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. *//* High-level class interface. */#include "config.h"#include "tree.h"#include <stdio.h>#include "cp-tree.h"#include "obstack.h"#include "flags.h"#include "rtl.h"#include "output.h"#define obstack_chunk_alloc xmalloc#define obstack_chunk_free freeextern struct obstack *current_obstack;extern tree abort_fndecl;#include "stack.h"/* Obstack used for remembering decision points of breadth-first. */static struct obstack search_obstack;/* Methods for pushing and popping objects to and from obstacks. */struct stack_level *push_stack_level (obstack, tp, size) struct obstack *obstack; char *tp; /* Sony NewsOS 5.0 compiler doesn't like void * here. */ int size;{ struct stack_level *stack; obstack_grow (obstack, tp, size); stack = (struct stack_level *) ((char*)obstack_next_free (obstack) - size); obstack_finish (obstack); stack->obstack = obstack; stack->first = (tree *) obstack_base (obstack); stack->limit = obstack_room (obstack) / sizeof (tree *); return stack;}struct stack_level *pop_stack_level (stack) struct stack_level *stack;{ struct stack_level *tem = stack; struct obstack *obstack = tem->obstack; stack = tem->prev; obstack_free (obstack, tem); return stack;}#define search_level stack_levelstatic struct search_level *search_stack;static void clear_memoized_cache PROTO((void));static tree make_memoized_table_entry PROTO((tree, tree, int));static tree get_abstract_virtuals_1 PROTO((tree, int, tree));static tree get_vbase_1 PROTO((tree, tree, unsigned int *));static tree convert_pointer_to_vbase PROTO((tree, tree));static tree lookup_field_1 PROTO((tree, tree));static tree convert_pointer_to_single_level PROTO((tree, tree));static int lookup_fnfields_1 PROTO((tree, tree));static int lookup_fnfields_here PROTO((tree, tree));static int is_subobject_of_p PROTO((tree, tree));static int hides PROTO((tree, tree));static tree virtual_context PROTO((tree, tree, tree));static tree get_template_base_recursive PROTO((tree, tree, tree, int));static void dfs_walk PROTO((tree, void (*) (tree), int (*) (tree)));static void envelope_add_decl PROTO((tree, tree, tree *));static int get_base_distance_recursive PROTO((tree, int, int, int, int *, tree *, tree, tree *, int, int *, int, int));static void expand_upcast_fixups PROTO((tree, tree, tree, tree, tree, tree, tree *));static void fixup_virtual_upcast_offsets PROTO((tree, tree, int, int, tree, tree, tree, tree, tree *));static int markedp PROTO((tree));static int unmarkedp PROTO((tree));static int numberedp PROTO((tree));static int unnumberedp PROTO((tree));static int marked_vtable_pathp PROTO((tree));static int unmarked_vtable_pathp PROTO((tree));static int marked_new_vtablep PROTO((tree));static int unmarked_new_vtablep PROTO((tree));static int dfs_debug_unmarkedp PROTO((tree));static void dfs_number PROTO((tree));static void dfs_unnumber PROTO((tree));static void dfs_debug_mark PROTO((tree));static void dfs_find_vbases PROTO((tree));static void dfs_clear_vbase_slots PROTO((tree));static void dfs_unmark PROTO((tree));static void dfs_init_vbase_pointers PROTO((tree));static void dfs_get_vbase_types PROTO((tree));static void dfs_record_inheritance PROTO((tree));static void dfs_pushdecls PROTO((tree));static void dfs_compress_decls PROTO((tree));static void dfs_unuse_fields PROTO((tree));static void add_conversions PROTO((tree));static tree get_virtuals_named_this PROTO((tree));static tree get_virtual_destructor PROTO((tree, int));static int tree_has_any_destructor_p PROTO((tree, int));static struct search_level *push_search_level PROTO((struct stack_level *, struct obstack *));static struct search_level *pop_search_level PROTO((struct stack_level *));static struct type_level *push_type_level PROTO((struct stack_level *, struct obstack *));static struct type_level *pop_type_level PROTO((struct type_level *));static tree my_tree_cons PROTO((tree, tree, tree));static tree my_build_string PROTO((char *));static struct memoized_entry * my_new_memoized_entry PROTO((struct memoized_entry *));static HOST_WIDE_INT breadth_first_search PROTO((tree, int (*) (tree, int), int (*) (tree, int)));static tree vbase_types;static tree vbase_decl_ptr_intermediate, vbase_decl_ptr;static tree vbase_init_result;/* Allocate a level of searching. */static struct search_level *push_search_level (stack, obstack) struct stack_level *stack; struct obstack *obstack;{ struct search_level tem; tem.prev = stack; return push_stack_level (obstack, (char *)&tem, sizeof (tem));}/* Discard a level of search allocation. */static struct search_level *pop_search_level (obstack) struct stack_level *obstack;{ register struct search_level *stack = pop_stack_level (obstack); return stack;}/* Search memoization. */struct type_level{ struct stack_level base; /* First object allocated in obstack of entries. */ char *entries; /* Number of types memoized in this context. */ int len; /* Type being memoized; save this if we are saving memoized contexts. */ tree type;};/* Obstack used for memoizing member and member function lookup. */static struct obstack type_obstack, type_obstack_entries;static struct type_level *type_stack;static tree _vptr_name;/* Make things that look like tree nodes, but allocate them on type_obstack_entries. */static int my_tree_node_counter;extern int flag_memoize_lookups, flag_save_memoized_contexts;/* Variables for gathering statistics. */static int my_memoized_entry_counter;static int memoized_fast_finds[2], memoized_adds[2], memoized_fast_rejects[2];static int memoized_fields_searched[2];#ifdef GATHER_STATISTICSstatic int n_fields_searched;static int n_calls_lookup_field, n_calls_lookup_field_1;static int n_calls_lookup_fnfields, n_calls_lookup_fnfields_1;static int n_calls_get_base_type;static int n_outer_fields_searched;static int n_contexts_saved;#endif /* GATHER_STATISTICS *//* Local variables to help save memoization contexts. */static tree prev_type_memoized;static struct type_level *prev_type_stack;/* This list is used by push_class_decls to know what decls need to be pushed into class scope. */static tree closed_envelopes = NULL_TREE;/* Allocate a level of type memoization context. */static struct type_level *push_type_level (stack, obstack) struct stack_level *stack; struct obstack *obstack;{ struct type_level tem; tem.base.prev = stack; obstack_finish (&type_obstack_entries); tem.entries = (char *) obstack_base (&type_obstack_entries); tem.len = 0; tem.type = NULL_TREE; return (struct type_level *)push_stack_level (obstack, (char *)&tem, sizeof (tem));}/* Discard a level of type memoization context. */static struct type_level *pop_type_level (stack) struct type_level *stack;{ obstack_free (&type_obstack_entries, stack->entries); return (struct type_level *)pop_stack_level ((struct stack_level *)stack);}/* Make something that looks like a TREE_LIST, but do it on the type_obstack_entries obstack. */static treemy_tree_cons (purpose, value, chain) tree purpose, value, chain;{ tree p = (tree)obstack_alloc (&type_obstack_entries, sizeof (struct tree_list)); ++my_tree_node_counter; TREE_TYPE (p) = NULL_TREE; ((HOST_WIDE_INT *)p)[3] = 0; TREE_SET_CODE (p, TREE_LIST); TREE_PURPOSE (p) = purpose; TREE_VALUE (p) = value; TREE_CHAIN (p) = chain; return p;}static treemy_build_string (str) char *str;{ tree p = (tree)obstack_alloc (&type_obstack_entries, sizeof (struct tree_string)); ++my_tree_node_counter; TREE_TYPE (p) = 0; ((int *)p)[3] = 0; TREE_SET_CODE (p, STRING_CST); TREE_STRING_POINTER (p) = str; TREE_STRING_LENGTH (p) = strlen (str); return p;}/* Memoizing machinery to make searches for multiple inheritance reasonably efficient. */#define MEMOIZE_HASHSIZE 8typedef struct memoized_entry{ struct memoized_entry *chain; int uid; tree data_members[MEMOIZE_HASHSIZE]; tree function_members[MEMOIZE_HASHSIZE];} *ME;#define MEMOIZED_CHAIN(ENTRY) (((ME)ENTRY)->chain)#define MEMOIZED_UID(ENTRY) (((ME)ENTRY)->uid)#define MEMOIZED_FIELDS(ENTRY,INDEX) (((ME)ENTRY)->data_members[INDEX])#define MEMOIZED_FNFIELDS(ENTRY,INDEX) (((ME)ENTRY)->function_members[INDEX])/* The following is probably a lousy hash function. */#define MEMOIZED_HASH_FN(NODE) (((long)(NODE)>>4)&(MEMOIZE_HASHSIZE - 1))static struct memoized_entry *my_new_memoized_entry (chain) struct memoized_entry *chain;{ struct memoized_entry *p = (struct memoized_entry *)obstack_alloc (&type_obstack_entries, sizeof (struct memoized_entry)); bzero ((char *) p, sizeof (struct memoized_entry)); MEMOIZED_CHAIN (p) = chain; MEMOIZED_UID (p) = ++my_memoized_entry_counter; return p;}/* Clears the deferred pop from pop_memoized_context, if any. */static voidclear_memoized_cache (){ if (prev_type_stack) { type_stack = pop_type_level (prev_type_stack); prev_type_memoized = 0; prev_type_stack = 0; }}/* Make an entry in the memoized table for type TYPE that the entry for NAME is FIELD. */static treemake_memoized_table_entry (type, name, function_p) tree type, name; int function_p;{ int idx = MEMOIZED_HASH_FN (name); tree entry, *prev_entry; /* Since we allocate from the type_obstack, we must pop any deferred levels. */ clear_memoized_cache (); memoized_adds[function_p] += 1; if (CLASSTYPE_MTABLE_ENTRY (type) == 0) { obstack_ptr_grow (&type_obstack, type); obstack_blank (&type_obstack, sizeof (struct memoized_entry *)); CLASSTYPE_MTABLE_ENTRY (type) = (char *)my_new_memoized_entry ((struct memoized_entry *)0); type_stack->len++; if (type_stack->len * 2 >= type_stack->base.limit) my_friendly_abort (88); } if (function_p) prev_entry = &MEMOIZED_FNFIELDS (CLASSTYPE_MTABLE_ENTRY (type), idx); else prev_entry = &MEMOIZED_FIELDS (CLASSTYPE_MTABLE_ENTRY (type), idx); entry = my_tree_cons (name, NULL_TREE, *prev_entry); *prev_entry = entry; /* Don't know the error message to give yet. */ TREE_TYPE (entry) = error_mark_node; return entry;}/* When a new function or class context is entered, we build a table of types which have been searched for members. The table is an array (obstack) of types. When a type is entered into the obstack, its CLASSTYPE_MTABLE_ENTRY field is set to point to a new record, of type struct memoized_entry. A non-NULL TREE_TYPE of the entry contains an access control error message. The slots for the data members are arrays of tree nodes. These tree nodes are lists, with the TREE_PURPOSE of this list the known member name, and the TREE_VALUE as the FIELD_DECL for the member. For member functions, the TREE_PURPOSE is again the name of the member functions for that class, and the TREE_VALUE of the list is a pairs whose TREE_PURPOSE is a member functions of this name, and whose TREE_VALUE is a list of known argument lists this member function has been called with. The TREE_TYPE of the pair, if non-NULL, is an error message to print. *//* Tell search machinery that we are entering a new context, and to update tables appropriately. TYPE is the type of the context we are entering, which can be NULL_TREE if we are not in a class's scope. USE_OLD, if nonzero tries to use previous context. */voidpush_memoized_context (type, use_old) tree type; int use_old;{ int len; tree *tem; if (prev_type_stack) { if (use_old && prev_type_memoized == type) {#ifdef GATHER_STATISTICS n_contexts_saved++;#endif /* GATHER_STATISTICS */ type_stack = prev_type_stack; prev_type_stack = 0; tem = &type_stack->base.first[0]; len = type_stack->len; while (len--) CLASSTYPE_MTABLE_ENTRY (tem[len*2]) = (char *)tem[len*2+1]; return; } /* Otherwise, need to pop old stack here. */ clear_memoized_cache (); } type_stack = push_type_level ((struct stack_level *)type_stack, &type_obstack); type_stack->type = type;}/* Tell search machinery that we have left a context. We do not currently save these contexts for later use. If we wanted to, we could not use pop_search_level, since poping that level allows the data we have collected to be clobbered; a stack of obstacks would be needed. */voidpop_memoized_context (use_old) int use_old;{ int len; tree *tem = &type_stack->base.first[0]; if (! flag_save_memoized_contexts) use_old = 0; else if (use_old) { len = type_stack->len; while (len--) tem[len*2+1] = (tree)CLASSTYPE_MTABLE_ENTRY (tem[len*2]); /* If there was a deferred pop, we need to pop it now. */ clear_memoized_cache (); prev_type_stack = type_stack; prev_type_memoized = type_stack->type; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -