From 17211ab55314d76370a68036f2d057b1effd687f Mon Sep 17 00:00:00 2001 From: Geoffrey Keating Date: Fri, 10 Jan 2003 02:22:34 +0000 Subject: Merge from pch-branch. From-SVN: r61136 --- gcc/ChangeLog | 520 +++++++++++- gcc/Makefile.in | 48 +- gcc/ada/ChangeLog | 6 + gcc/ada/ada-tree.h | 3 +- gcc/ada/gnat_rm.texi | 2 - gcc/c-common.c | 10 + gcc/c-common.h | 26 +- gcc/c-decl.c | 8 +- gcc/c-lex.c | 4 + gcc/c-objc-common.c | 5 +- gcc/c-opts.c | 16 + gcc/c-parse.in | 6 +- gcc/c-pch.c | 226 ++++++ gcc/config/alpha/alpha.c | 46 +- gcc/config/darwin.c | 2 +- gcc/config/rs6000/rs6000.c | 88 +- gcc/config/rs6000/t-rs6000 | 5 +- gcc/cp/ChangeLog | 90 +++ gcc/cp/Make-lang.in | 25 +- gcc/cp/call.c | 1 - gcc/cp/class.c | 133 +++- gcc/cp/cp-tree.h | 27 +- gcc/cp/decl.c | 3 +- gcc/cp/decl2.c | 4 +- gcc/cp/g++spec.c | 96 ++- gcc/cp/init.c | 1 - gcc/cp/lang-specs.h | 13 + gcc/cp/lex.c | 6 +- gcc/cp/method.c | 5 +- gcc/cp/optimize.c | 1 - gcc/cp/parser.c | 68 +- gcc/cp/pt.c | 1 - gcc/cp/repo.c | 1 - gcc/cp/search.c | 1 - gcc/cp/semantics.c | 5 +- gcc/cp/tree.c | 1 - gcc/cppfiles.c | 115 ++- gcc/cpphash.h | 6 + gcc/cpplib.c | 84 ++ gcc/cpplib.h | 35 +- gcc/cpppch.c | 684 ++++++++++++++++ gcc/dbxout.c | 139 ++-- gcc/doc/cppopts.texi | 11 + gcc/doc/gty.texi | 36 +- gcc/doc/invoke.texi | 134 +++- gcc/doc/passes.texi | 44 +- gcc/dwarf2asm.c | 38 +- gcc/dwarf2out.c | 488 +++++++----- gcc/emit-rtl.c | 12 +- gcc/fold-const.c | 2 +- gcc/function.c | 2 +- gcc/gcc.c | 30 +- gcc/gengtype.c | 1500 ++++++++++++++++++++++------------- gcc/ggc-common.c | 553 ++++++++++--- gcc/ggc-page.c | 258 +++++- gcc/ggc-simple.c | 85 +- gcc/ggc.h | 184 +++-- gcc/java/ChangeLog | 74 ++ gcc/java/Make-lang.in | 8 +- gcc/java/config-lang.in | 2 +- gcc/java/constants.c | 64 +- gcc/java/gjavah.c | 1 + gcc/java/java-tree.h | 10 +- gcc/java/jcf-dump.c | 1 + gcc/java/jcf-parse.c | 49 +- gcc/java/jcf-reader.c | 18 +- gcc/java/jcf.h | 49 +- gcc/java/lex.c | 2 +- gcc/java/lex.h | 7 +- gcc/java/parse.h | 33 +- gcc/java/parse.y | 76 +- gcc/mkdeps.c | 74 ++ gcc/mkdeps.h | 11 + gcc/objc/objc-act.c | 1 + gcc/optabs.h | 4 +- gcc/stringpool.c | 93 ++- gcc/testsuite/ChangeLog | 84 ++ gcc/testsuite/g++.dg/dg.exp | 1 + gcc/testsuite/g++.dg/pch/empty.C | 5 + gcc/testsuite/g++.dg/pch/empty.H | 0 gcc/testsuite/g++.dg/pch/pch.exp | 100 +++ gcc/testsuite/g++.dg/pch/system-1.C | 7 + gcc/testsuite/g++.dg/pch/system-1.H | 1 + gcc/testsuite/gcc.dg/pch/common-1.c | 3 + gcc/testsuite/gcc.dg/pch/common-1.h | 3 + gcc/testsuite/gcc.dg/pch/cpp-1.c | 4 + gcc/testsuite/gcc.dg/pch/cpp-1.h | 1 + gcc/testsuite/gcc.dg/pch/cpp-2.c | 4 + gcc/testsuite/gcc.dg/pch/cpp-2.h | 1 + gcc/testsuite/gcc.dg/pch/decl-1.c | 2 + gcc/testsuite/gcc.dg/pch/decl-1.h | 1 + gcc/testsuite/gcc.dg/pch/decl-2.c | 2 + gcc/testsuite/gcc.dg/pch/decl-2.h | 3 + gcc/testsuite/gcc.dg/pch/decl-3.c | 11 + gcc/testsuite/gcc.dg/pch/decl-3.h | 3 + gcc/testsuite/gcc.dg/pch/decl-4.c | 9 + gcc/testsuite/gcc.dg/pch/decl-4.h | 7 + gcc/testsuite/gcc.dg/pch/decl-5.c | 2 + gcc/testsuite/gcc.dg/pch/decl-5.h | 1 + gcc/testsuite/gcc.dg/pch/empty.c | 8 + gcc/testsuite/gcc.dg/pch/empty.h | 0 gcc/testsuite/gcc.dg/pch/except-1.c | 7 + gcc/testsuite/gcc.dg/pch/except-1.h | 6 + gcc/testsuite/gcc.dg/pch/global-1.c | 2 + gcc/testsuite/gcc.dg/pch/global-1.h | 1 + gcc/testsuite/gcc.dg/pch/inline-1.c | 10 + gcc/testsuite/gcc.dg/pch/inline-1.h | 5 + gcc/testsuite/gcc.dg/pch/inline-2.c | 12 + gcc/testsuite/gcc.dg/pch/inline-2.h | 5 + gcc/testsuite/gcc.dg/pch/macro-1.c | 6 + gcc/testsuite/gcc.dg/pch/macro-1.h | 2 + gcc/testsuite/gcc.dg/pch/macro-2.c | 8 + gcc/testsuite/gcc.dg/pch/macro-2.h | 2 + gcc/testsuite/gcc.dg/pch/macro-3.c | 8 + gcc/testsuite/gcc.dg/pch/macro-3.h | 2 + gcc/testsuite/gcc.dg/pch/pch.exp | 100 +++ gcc/testsuite/gcc.dg/pch/static-1.c | 6 + gcc/testsuite/gcc.dg/pch/static-1.h | 5 + gcc/testsuite/gcc.dg/pch/static-2.c | 6 + gcc/testsuite/gcc.dg/pch/static-2.h | 5 + gcc/testsuite/gcc.dg/pch/system-1.c | 6 + gcc/testsuite/gcc.dg/pch/system-1.h | 2 + gcc/testsuite/lib/g++-dg.exp | 4 + gcc/testsuite/lib/gcc-dg.exp | 4 + gcc/toplev.c | 2 +- gcc/tree.c | 4 +- gcc/tree.h | 8 +- gcc/varasm.c | 23 +- 128 files changed, 5484 insertions(+), 1550 deletions(-) create mode 100644 gcc/c-pch.c create mode 100644 gcc/cpppch.c create mode 100644 gcc/testsuite/g++.dg/pch/empty.C create mode 100644 gcc/testsuite/g++.dg/pch/empty.H create mode 100644 gcc/testsuite/g++.dg/pch/pch.exp create mode 100644 gcc/testsuite/g++.dg/pch/system-1.C create mode 100644 gcc/testsuite/g++.dg/pch/system-1.H create mode 100644 gcc/testsuite/gcc.dg/pch/common-1.c create mode 100644 gcc/testsuite/gcc.dg/pch/common-1.h create mode 100644 gcc/testsuite/gcc.dg/pch/cpp-1.c create mode 100644 gcc/testsuite/gcc.dg/pch/cpp-1.h create mode 100644 gcc/testsuite/gcc.dg/pch/cpp-2.c create mode 100644 gcc/testsuite/gcc.dg/pch/cpp-2.h create mode 100644 gcc/testsuite/gcc.dg/pch/decl-1.c create mode 100644 gcc/testsuite/gcc.dg/pch/decl-1.h create mode 100644 gcc/testsuite/gcc.dg/pch/decl-2.c create mode 100644 gcc/testsuite/gcc.dg/pch/decl-2.h create mode 100644 gcc/testsuite/gcc.dg/pch/decl-3.c create mode 100644 gcc/testsuite/gcc.dg/pch/decl-3.h create mode 100644 gcc/testsuite/gcc.dg/pch/decl-4.c create mode 100644 gcc/testsuite/gcc.dg/pch/decl-4.h create mode 100644 gcc/testsuite/gcc.dg/pch/decl-5.c create mode 100644 gcc/testsuite/gcc.dg/pch/decl-5.h create mode 100644 gcc/testsuite/gcc.dg/pch/empty.c create mode 100644 gcc/testsuite/gcc.dg/pch/empty.h create mode 100644 gcc/testsuite/gcc.dg/pch/except-1.c create mode 100644 gcc/testsuite/gcc.dg/pch/except-1.h create mode 100644 gcc/testsuite/gcc.dg/pch/global-1.c create mode 100644 gcc/testsuite/gcc.dg/pch/global-1.h create mode 100644 gcc/testsuite/gcc.dg/pch/inline-1.c create mode 100644 gcc/testsuite/gcc.dg/pch/inline-1.h create mode 100644 gcc/testsuite/gcc.dg/pch/inline-2.c create mode 100644 gcc/testsuite/gcc.dg/pch/inline-2.h create mode 100644 gcc/testsuite/gcc.dg/pch/macro-1.c create mode 100644 gcc/testsuite/gcc.dg/pch/macro-1.h create mode 100644 gcc/testsuite/gcc.dg/pch/macro-2.c create mode 100644 gcc/testsuite/gcc.dg/pch/macro-2.h create mode 100644 gcc/testsuite/gcc.dg/pch/macro-3.c create mode 100644 gcc/testsuite/gcc.dg/pch/macro-3.h create mode 100644 gcc/testsuite/gcc.dg/pch/pch.exp create mode 100644 gcc/testsuite/gcc.dg/pch/static-1.c create mode 100644 gcc/testsuite/gcc.dg/pch/static-1.h create mode 100644 gcc/testsuite/gcc.dg/pch/static-2.c create mode 100644 gcc/testsuite/gcc.dg/pch/static-2.h create mode 100644 gcc/testsuite/gcc.dg/pch/system-1.c create mode 100644 gcc/testsuite/gcc.dg/pch/system-1.h (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index edae831..2e2e1b2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,519 @@ +2003-01-09 Geoffrey Keating + + Merge from pch-branch: + + 2003-01-06 Geoffrey Keating + + * ggc-page.c (ggc_pch_read): Update the statistics after a PCH + load. + + 2002-12-24 Geoffrey Keating + + * cpplib.c (count_registered_pragmas): New function. + (save_registered_pragmas): New function. + (_cpp_save_pragma_names): New function. + (restore_registered_pragmas): New function. + (_cpp_restore_pragma_names): New function. + * cpphash.h (_cpp_save_pragma_names): Prototype. + (_cpp_restore_pragma_names): Likewise. + * cpppch.c (struct save_macro_item): Split from save_macro_data. + (struct save_macro_data): New field 'saved_pragmas'. + (save_macros): Update for changes to struct save_macro_data. + (cpp_prepare_state): Call _cpp_save_pragma_names, update + for changes to struct save_macro_data. + (cpp_read_state): Call _cpp_restore_pragma_names, update + for changes to struct save_macro_data. + + * cpppch.c (cpp_read_state): Restore the hashtable references + in the cpp_reader. + + * tree.h (built_in_decls): Mark for PCH. + + * dbxout.c (lastfile): Don't mark for PCH. + + * ggc.h: Document PCH calls into memory managers. + + 2002-12-18 Geoffrey Keating + + * doc/invoke.texi (Precompiled Headers): Document the + directory form of PCH. + * cppfiles.c (validate_pch): New function. + (open_file_pch): Search suitably-named directories for PCH files. + + 2002-12-14 Geoffrey Keating + + * doc/gty.texi (GTY Options): Document chain_next, chain_prev, + reorder options. + (Type Information): Mention that the information is also + used to implement PCH. + * doc/passes.texi (Passes): Improve documentation of + language-specific files. + + 2002-12-11 Geoffrey Keating + + * gengtype.c (struct write_types_data): Add reorder_note_routine field. + (struct walk_type_data): Add reorder_fn field. + (walk_type): Process 'reorder' option. + (write_types_process_field): Reorder parameters to gt_pch_note_object, + call reorder_note_routine. + (write_func_for_structure): Reorder parameters to gt_pch_note_object. + (ggc_wtd): Update for change to struct write_types_data. + (pch_wtd): Likewise. + * ggc.h (gt_pch_note_object): Reorder parameters. + (gt_handle_reorder): New definition. + (gt_pch_note_reorder): New prototype. + * ggc-common.c (struct ptr_data): Add reorder_fn. + (gt_pch_note_object): Reorder parameters. + (gt_pch_note_reorder): New. + (gt_pch_save): Call reorder_fn. + * stringpool.c (gt_pch_n_S): Update for change to gt_pch_note_object. + + * dbxout.c (cwd): Don't mark for PCH. + + 2002-12-09 Geoffrey Keating + + * gengtype.c (finish_root_table): Fix some warnings. + (write_root): Handle TYPE_STRING. + * ggc.h (gt_ggc_m_S): Add prototype. + * stringpool.c (gt_ggc_m_S): New function. + + 2002-11-30 Geoffrey Keating + + * dwarf2out.c (dw2_string_counter): New. + (AT_string_form): Use it. + (same_dw_val_p): Update for removal of hashtable.h hash tables. + + 2002-11-22 Geoffrey Keating + + * dbxout.c: Include gt-dbxout.h. + (lastfile): Mark for PCH/GGC. + (cwd): Likewise. + (struct typeinfo): Likewise. + (typevec): Likewise. + (typevec_len): Likewise. + (next_type_number): Likewise. + (struct dbx_file): Likewise. + (current_file): Likewise. + (next_file_number): Likewise. + (dbxout_init): Allocate typevec, struct dbx_file with GGC. + (dbxout_start_source_file): Allocate struct dbx_file with GGC. + (dbxout_end_source_file): Don't free struct dbx_file. + (dbxout_type): Use GGC to allocate typevec. + * Makefile.in (dbxout.o): Depend on gt-dbxout.h, $(GGC_H). + (GTFILES): Add dbxout.c. + (gt-dbxout.h): New rule. + + * Makefile.in (c-pch.o): Add debug.h as dependency. + * c-pch.c: Include debug.h. + (pch_init): Call start_source_file to keep nesting right. + (c_common_read_pch): Add orig_name parameter. Call + start_source_file debug hook. Call end_source_file debug hook. + * c-common.h (c_common_read_pch): Update prototype. + * cpplib.h (struct cpp_callbacks): Add fourth field to read_pch + callback. + * cppfiles.c (struct include_file): Add new field `header_name'. + (find_or_create_entry): Default it to `name'. + (open_file_pch): Set it to the original header file searched for. + (stack_include_file): Don't stack an empty buffer, just handle + PCH files immediately. Pass header_name field to read_pch callback. + + 2002-11-19 Geoffrey Keating + + * function.c (funcdef_no): Mark to be saved in a PCH. + + 2002-11-15 Geoffrey Keating + + * ggc-page.c (ggc_pch_read): Remove unused 'bmap_size'. + + * cpppch.c (cpp_read_state): Correct size reallocated for 'defn'. + + 2002-11-14 Geoffrey Keating + + * optabs.h (code_to_optab): Add GTY marker. + + 2002-11-13 Geoffrey Keating + + * Makefile.in (GTFILES): Add cpplib.h. + * c-common.h (struct c_common_identifier): Don't skip 'node' field. + * c-decl.c (build_compound_literal): Don't use var_labelno. + * cpplib.h (struct cpp_hashnode): Use gengtype to mark. + * dwarf2asm.c (dw2_force_const_mem): Don't use const_labelno. + * varasm.c (const_labelno): Use gengtype to mark. + (var_labelno): Likewise. + (in_section): Likewise. + (in_named_name): Likewise. + (struct in_named_entry): Likewise. + (in_named_htab): Likewise. + (set_named_section_flags): Use GGC to allocate struct in_named_entry. + (init_varasm_once): Use GGC to allocate in_named_htab. + * config/darwin.c (current_pic_label_num): Mark for PCH. + + 2002-11-11 Geoffrey Keating + + * ggc-simple.c (init_ggc_pch): New stub procedure. + (ggc_pch_count_object): Likewise. + (ggc_pch_total_size): Likewise. + (ggc_pch_this_base): Likewise. + (ggc_pch_alloc_object): Likewise. + (ggc_pch_prepare_write): Likewise. + (ggc_pch_write_object): Likewise + (ggc_pch_finish): Likewise. + (ggc_pch_read): Likewise. + + 2002-11-08 Geoffrey Keating + + * c-pch.c (c_common_write_pch): Write the macro definitions after + the GCed data. + (c_common_read_pch): Call cpp_prepare_state. Restore the macro + definitions after the GCed data. + * cpplib.c (save_macros): New. + (reset_ht): New. + (cpp_write_pch_deps): Split out of cpp_write_pch. + (cpp_write_pch_state): Split out of cpp_write_pch. + (cpp_write_pch): Delete. + (struct save_macro_data): Delete. + (cpp_prepare_state): New. + (cpp_read_state): Erase and restore initial macro definitions. + * cpplib.h (struct save_macro_data): Forward-declare. + (cpp_write_pch_deps): Prototype. + (cpp_write_pch_state): Prototype. + (cpp_write_pch): Delete prototype. + (cpp_prepare_state): Prototype. + (cpp_read_state): Add fourth argument. + + 2002-11-04 Geoffrey Keating + + * gengtype.c (adjust_field_rtx_def): Don't use skip on valid fields. + (write_array): Remove warning. + + * gengtype.c (contains_scalar_p): New. + (finish_root_table): Add the table to all languages, even if it's + empty. + (write_roots): Output gt_pch_scalar_rtab. + * ggc-common.c (gt_pch_save): Write out scalars. + (gt_pch_restore): Read scalars back. + + * ggc-page.c (OBJECTS_IN_PAGE): New macro. + (struct page_entry): Delete pch_page field. + (ggc_recalculate_in_use_p): Use OBJECTS_IN_PAGE. + (clear_marks): Likewise. + (sweep_pages): Likewise. + (poison_pages): Likewise. + (ggc_print_statistics): Likewise. + (ggc_pch_read): Don't free objects read from a PCH. + Properly set up in_use_p and page_tails. + + 2002-10-25 Geoffrey Keating + + * gengtype.c (struct write_types_data): New. + (struct walk_type_data): Make `cookie' const; add extra + prev_val item; add `orig_s' field. + (walk_type): Update prev_val[3]. + (write_types_process_field): New. + (write_func_for_structure): Take write_types_data structure. + (write_types): New. + (ggc_wtd): New. + (pch_wtd): New. + (write_types_local_process_field): New. + (gc_mark_process_field): Delete. + (write_local_func_for_structure): New. + (gc_mark_func_name): Delete. + (write_gc_types): Delete. + (write_local): New. + (finish_root_table): Don't include 'ggc_' in PFX. + (write_root): Rename from write_root. Fill pchw field of structures. + (write_array): New. + (write_roots): Rename from write_gc_roots. Split out to write_array. + Update to changes to other routines. Write gt_pch_cache_rtab table. + (main): Write PCH walking routines. + * ggc-common.c: Include toplev.h, sys/mman.h. + (ggc_mark_roots): For cache hashtables, also mark the hash table + and the array of entries. + (saving_htab): New. + (struct ptr_data): New. + (POINTER_HASH): New. + (gt_pch_note_object): New. + (saving_htab_hash): New. + (saving_htab_eq): New. + (struct traversal_state): New. + (call_count): New. + (call_alloc): New. + (compare_ptr_data): New. + (relocate_ptrs): New. + (write_pch_globals): New. + (struct mmap_info): New. + (gt_pch_save): New. + (gt_pch_restore): New. + * ggc-page.c (ROUND_UP_VALUE): New. + (ROUND_UP): New. + (struct page_entry): Add field `pch_page'. + (init_ggc): Use ROUND_UP. + (struct ggc_pch_data): Declare. + (init_ggc_pch): New. + (ggc_pch_count_object): New. + (ggc_pch_total_size): New. + (ggc_pch_this_base): New. + (ggc_pch_alloc_object): New. + (ggc_pch_prepare_write): New. + (ggc_pch_write_object): New. + (ggc_pch_finish): New. + (ggc_pch_read): New. + * ggc.h (gt_pointer_operator): New. + (gt_note_pointers): New. + (gt_pch_note_object): New prototype. + (gt_pointer_walker): New. + (struct ggc_root_tab): Use gt_pointer_walker, add `pchw' field. + (LAST_GGC_ROOT_TAB): Update. + (gt_pch_cache_rtab): Declare. + (gt_pch_scalar_rtab): Declare. + (struct ggc_cache_tab): Use gt_pointer_walker, add `pchw' field. + (LAST_GGC_CACHE_TAB): Update. + (gt_pch_save_stringpool): Declare. + (gt_pch_restore_stringpool): Declare. + (gt_pch_p_S): Declare. + (gt_pch_n_S): Declare. + (struct ggc_pch_data): Forward-declare. + (init_ggc_pch): Declare. + (ggc_pch_count_object): Declare. + (ggc_pch_total_size): Declare. + (ggc_pch_this_base): Declare. + (ggc_pch_alloc_object): Declare. + (ggc_pch_prepare_write): Declare. + (ggc_pch_write_object): Declare. + (ggc_pch_finish): Declare. + (ggc_pch_read): Declare. + (gt_pch_save): Declare. + (gt_pch_restore): Declare. + * fold-const.c (size_int_type_wide): Allocate size_htab using GGC. + * emit-rtl.c (init_emit_once): Allocate const_int_htab, + const_double_htab, mem_attrs_htab using GGC. + * c-pch.c: Include ggc.h. + (pch_init): Allow reading PCH file back. + (c_common_write_pch): Call gt_pch_save. + (c_common_read_pch): Call gt_pch_restore. + * c-parse.in (init_reswords): Delete now-untrue comment. + Allocate ridpointers using GGC. + * c-objc-common.c (c_objc_common_finish_file): Write PCH before + calling expand_deferred_fns. + * c-common.h (ridpointers): Mark for GTY machinery. + * Makefile.in (stringpool.o): Update dependencies. + (c-pch.o): Update dependencies. + (ggc-common.o): Update dependencies. + * stringpool.c: Include gt-stringpool.h. + (gt_pch_p_S): New. + (gt_pch_n_S): New. + (struct string_pool_data): New. + (spd): New. + (gt_pch_save_stringpool): New. + (gt_pch_restore_stringpool): New. + * tree.c (init_ttree): Make type_hash_table allocated using GC. + + 2002-10-04 Geoffrey Keating + + * gengtype.c (adjust_field_rtx_def): Don't pass size_t to printf. + (output_mangled_typename): Don't pass size_t to printf. + + * tree.h (union tree_type_symtab): Add tag to `address' field. + (union tree_decl_u2): Add tag to 'i' field. + * varasm.c (union rtx_const_un): Add tags to all fields. + * gengtype.c (struct walk_type_data): New. + (output_escaped_param): Take struct walk_type_data parameter. + (write_gc_structure_fields): Delete. + (walk_type): New. + (write_gc_marker_routine_for_structure): Delete. + (write_func_for_structure): New. + (gc_mark_process_field): New. + (gc_mark_func_name): New. + (gc_counter): Delete. + (write_gc_types): Use write_func_for_structure. + (write_gc_roots): Use walk_type. + + 2002-10-02 Geoffrey Keating + + * ggc-common.c (ggc_mark_roots): Delete 'x'. + (ggc_splay_dont_free): Fix warning about unused 'x'. + (ggc_print_common_statistics): Remove warnings. + + 2002-10-01 Mike Stump + + * ggc-common.c (ggc_splay_alloc): Actually return the allocated area. + * gengtype.c (write_gc_structure_fields): Handle param[digit]_is. + + 2002-09-01 Geoffrey Keating + Catherine Moore + + * Makefile (c-pch.o): Update dependencies. + (LIBCPP_OBJS): Add cpppch.o. + (cpppch.o): New. + * c-common.c (c_common_init): Don't call pch_init here. + * c-common.h (c_common_read_pch): Update prototype. + * c-lex.c (c_common_parse_file): Call pch_init here. + * c-opts.c (COMMAND_LINE_OPTIONS): Add -Winvalid-pch, -fpch-deps. + (c_common_decode_option): Handle them. + * c-pch.c: Include c-pragma.h. + (save_asm_offset): Delete. + (pch_init): Move contents of save_asm_offset into here, call + cpp_save_state. + (c_common_write_pch): Call cpp_write_pch. + (c_common_valid_pch): Warn only when -Winvalid-pch. Call + cpp_valid_state. + (c_common_read_pch): Add NAME parameter. Call cpp_read_state. + * cppfiles.c (stack_include_file): Update for change to + parameters of cb.read_pch. + * cpphash.h (struct cpp_reader): Add `savedstate' field. + * cpplib.h (struct cpp_options): Add `warn_invalid_pch' and + `restore_pch_deps' fields. + (struct cpp_callbacks): Add NAME parameter to `read_pch'. + (cpp_save_state): Prototype. + (cpp_write_pch): Prototype. + (cpp_valid_state): Prototype. + (cpp_read_state): Prototype. + * cpppch.c: New file. + * flags.h (version_flag): Remove prototype. + * mkdeps.c (deps_save): New. + (deps_restore): New. + * mkdeps.h (deps_save): Prototype. + (deps_restore): Prototype. + * toplev.c (late_init_hook): Delete. + (version_flag): Make static again. + (compile_file): Don't call late_init_hook. + * toplev.h (late_init_hook): Delete. + * doc/cppopts.texi: Document -fpch-deps. + * doc/invoke.texi (Warning Options): Document -Winvalid-pch. + + 2002-08-27 Geoffrey Keating + + * c-pch.c (c_common_write_pch): Rename from c_write_pch, change + callers. + (c_common_valid_pch): Rename from c_valid_pch, change callers. + (c_common_read_pch): Rename from c_read_pch, change callers. + + * c-opts.c (COMMAND_LINE_OPTIONS): Allow -output-pch= to have + a space between it and its argument. + + 2002-08-24 Geoffrey Keating + + * c-pch.c: New file. + * toplev.h (late_init_hook): Declare. + * toplev.c (late_init_hook): Define. + (version_flag): Make globally visible. + (compile_file): Call late_init_hook. + (init_asm_output): Make output file seekable. + * gcc.c (default_compilers): Update c-header rule. + * flags.h (version_flag): Declare. + * cpplib.h (struct cpp_callbacks): Add 'valid_pch' and 'read_pch' + fields. + * cppfiles.c (struct include_file): Add 'pch' field. + (INCLUDE_PCH_P): New. + (open_file_pch): New. + (stack_include_file): Handle PCH files specially. + (find_include_file): Call open_file_pch instead of open_file. + (_cpp_read_file): Explain why open_file is used instead of + open_file_pch. + * c-opts.c (c_common_decode_option): Correct OPT__output_pch case. + * c-objc-common.c (c_objc_common_finish_file): Call c_write_pch. + * c-lex.c (init_c_lex): Set valid_pch and read_pch fields + in cpplib callbacks. + * c-common.c (pch_file): Correct comment. + (allow_pch): Define. + (c_common_init): Call pch_init. + * c-common.h (allow_pch): Declare. + (pch_init): Declare. + (c_valid_pch): Declare. + (c_read_pch): Declare. + (c_write_pch): Declare. + * Makefile.in (c-pch.o): New. + (C_AND_OBJC_OBJS): Add c-pch.o. + * doc/invoke.texi (Precompiled Headers): Add index entries, + complete truncated paragraph. + + 2002-08-17 Geoffrey Keating + + * c-common.c: (pch_file): Define. + * c-common.h (pch_file): Declare. + * c-opts.c (COMMAND_LINE_OPTIONS): Add --output-pch=. + (missing_arg): Require --output-pch= to have an argument. + (c_common_decode_option): Handle --output-pch=. + * gcc.c: Document new %V. + (default_compilers): Handle compiling C header files. + (do_spec_1): Implement %V. + (main): Handle "gcc foo.h" without trying to run linker. + * doc/invoke.texi (Invoking GCC): Add new menu item for PCH. + (Overall Options): Document what the driver does with header files, + document new -x option possibilities. + (Invoking G++): More documentation for PCH. + (Precompiled Headers): New. + + 2002-08-09 Geoffrey Keating + + * ggc.h: Don't include varray.h. Rearrange functions to be more + organized. + (ggc_add_root): Delete. + (ggc_mark_rtx): Delete. + (ggc_mark_tree): Delete. + (struct ggc_statistics): Remove contents. + * ggc-common.c: Remove unneeded includes. + (struct ggc_root): Delete. + (roots): Delete. + (ggc_add_root): Delete. + (ggc_mark_roots): Don't mark `roots'. Call ggc_mark_stringpool. + (ggc_print_common_statistics): Remove most of the contents. + * Makefile.in (GGC_H): No longer uses varray.h. + (ggc-common.o): Update dependencies. + (c-parse.o): Add varray.h to dependencies. + (c-common.o): Add varray.h. + * stringpool.c (mark_ident): Use mangled name for tree marker routine. + (mark_ident_hash): Rename to ggc_mark_stringpool. + (init_stringpool): Don't use ggc_add_root. + * c-parse.in: Include varray.h. + * c-common.c: Include varray.h. + * objc/Make-lang.in (objc-act.o): Add varray.h. + * objc/objc-act.c: Include varray.h. + + 2002-07-25 Geoffrey Keating + + * dwarf2out.c (dw_cfi_oprnd2_desc): Fix ISO-only function definition. + (dw_cfi_oprnd1_desc): Likewise. + + 2002-07-17 Geoffrey Keating + + * config/alpha/alpha.c (struct alpha_links): Use gengtype to mark; + move out of ifdef. + (alpha_links): Use gengtype to mark; move out of ifdef. + (mark_alpha_links_node): Delete. + (mark_alpha_links): Delete. + (alpha_need_linkage): Use GGC to allocate splay tree, struct + alpha_links, strings. Don't use ggc_add_root. + * ggc-common.c (ggc_splay_alloc): New. + (ggc_splay_dont_free): New. + * ggc.h (ggc_mark_rtx): Update for changed name mangling. + (ggc_mark_tree): Likewise. + (splay_tree_new_ggc): New. + (ggc_splay_alloc): Declare. + (ggc_splay_dont_free): Declare. + * dwarf2asm.c: Include gt-dwarf2asm.h. + (mark_indirect_pool_entry): Delete. + (mark_indirect_pool): Delete. + (indirect_pool): Use gengtype to mark. + (dw2_force_const_mem): Don't use ggc_add_root. + * Makefile.in (dwarf2asm.o): Depend on gt-dwarf2asm.h. + (GTFILES): Add SPLAY_TREE_H, dwarf2asm.c. + (gt-dwarf2asm.h): Depend on s-gtype. + + 2002-07-08 Geoffrey Keating + + * tree.h (union tree_type_symtab): Mark `die' field. + * Makefile.in (dwarf2out.o): Update dependencies. + * dwarf2out.c: Use GGC to allocate all structures. Convert to htab_t + hash tables. + (dw_cfi_oprnd1_desc): New function. + (dw_cfi_oprnd2_desc): New function. + (indirect_string_alloc): Delete. + (debug_str_do_hash): New function. + (debug_str_eq): New function. + (mark_limbo_die_list): Delete. + (dwarf2out_init): Don't call ggc_add_root. + 2003-01-09 Vladimir Makarov The following changes are merged from itanium-sched-branch: @@ -438,10 +954,10 @@ the generated code. (write_automata): Call the new function. - Thu Jan 9 22:47:38 CET 2003 Jan Hubicka - * i386.md (unit, prefix_0f, memory attributes): Hanlde sseicvt correctly. + * i386.md (unit, prefix_0f, memory attributes): Hanlde sseicvt + correctly. 2003-01-09 Paolo Carlini diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 5ffdce2..c48d41c 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -587,7 +587,7 @@ REGS_H = regs.h varray.h $(MACHMODE_H) INTEGRATE_H = integrate.h varray.h LOOP_H = loop.h varray.h bitmap.h GCC_H = gcc.h version.h -GGC_H = ggc.h varray.h gtype-desc.h +GGC_H = ggc.h gtype-desc.h TIMEVAR_H = timevar.h timevar.def INSN_ATTR_H = insn-attr.h $(srcdir)/insn-addr.h $(srcdir)/varray.h C_COMMON_H = c-common.h $(SPLAY_TREE_H) $(CPPLIB_H) @@ -739,7 +739,7 @@ CXX_TARGET_OBJS=@cxx_target_objs@ # Language-specific object files for C and Objective C. C_AND_OBJC_OBJS = attribs.o c-errors.o c-lex.o c-pragma.o c-decl.o c-typeck.o \ c-convert.o c-aux-info.o c-common.o c-opts.o c-format.o c-semantics.o \ - c-objc-common.o c-dump.o libcpp.a $(C_TARGET_OBJS) + c-objc-common.o c-dump.o c-pch.o libcpp.a $(C_TARGET_OBJS) # Language-specific object files for C. C_OBJS = c-parse.o c-lang.o c-pretty-print.o $(C_AND_OBJC_OBJS) @@ -1175,7 +1175,7 @@ c-errors.o: c-errors.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(C_TREE_H) flags.h diagnostic.h $(TM_P_H) c-parse.o : $(srcdir)/c-parse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(GGC_H) intl.h $(C_TREE_H) input.h flags.h toplev.h output.h $(CPPLIB_H) \ - gt-c-parse.h + varray.h gt-c-parse.h $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ -c $(srcdir)/c-parse.c $(OUTPUT_OPTION) @@ -1246,7 +1246,7 @@ tlink.o: tlink.c $(DEMANGLE_H) $(HASHTAB_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h c-common.o : c-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(OBSTACK_H) $(C_COMMON_H) flags.h toplev.h output.h c-pragma.h $(RTL_H) \ $(GGC_H) $(EXPR_H) $(TM_P_H) builtin-types.def builtin-attrs.def $(TARGET_H) \ - diagnostic.h except.h gt-c-common.h real.h langhooks.h + diagnostic.h except.h gt-c-common.h real.h langhooks.h varray.h c-pretty-print.o : c-pretty-print.c c-pretty-print.h pretty-print.h \ $(C_COMMON_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) real.h @@ -1270,6 +1270,9 @@ c-semantics.o : c-semantics.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE c-dump.o : c-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(C_TREE_H) tree-dump.h +c-pch.o : c-pch.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(CPPLIB_H) $(TREE_H) \ + c-common.h output.h toplev.h c-pragma.h $(GGC_H) debug.h + # Language-independent files. DRIVER_DEFINES = \ @@ -1349,18 +1352,17 @@ gtype-desc.o: gtype-desc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) varray.h libfuncs.h debug.h $(GGC_H) bitmap.h $(BASIC_BLOCK_H) hard-reg-set.h \ ssa.h cselib.h insn-addr.h -ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ - flags.h $(GGC_H) varray.h $(HASHTAB_H) $(TM_P_H) langhooks.h \ - $(PARAMS_H) +ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GGC_H) \ + $(HASHTAB_H) toplev.h ggc-simple.o: ggc-simple.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ flags.h $(GGC_H) varray.h $(TIMEVAR_H) $(TM_P_H) $(PARAMS_H) ggc-page.o: ggc-page.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ - flags.h toplev.h $(GGC_H) varray.h $(TIMEVAR_H) $(TM_P_H) + flags.h toplev.h $(GGC_H) varray.h $(TIMEVAR_H) $(TM_P_H) $(PARAMS_H) -stringpool.o: stringpool.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(OBSTACK_H) flags.h toplev.h $(GGC_H) +stringpool.o: stringpool.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(TREE_H) $(GGC_H) gt-stringpool.h hashtable.o: hashtable.c hashtable.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(OBSTACK_H) @@ -1466,11 +1468,12 @@ optabs.o : optabs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_ toplev.h $(GGC_H) real.h $(TM_P_H) except.h gt-optabs.h $(BASIC_BLOCK_H) dbxout.o : dbxout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \ flags.h $(REGS_H) debug.h $(TM_P_H) $(TARGET_H) function.h langhooks.h \ - insn-config.h reload.h gstab.h xcoffout.h output.h dbxout.h toplev.h + insn-config.h reload.h gstab.h xcoffout.h output.h dbxout.h toplev.h \ + $(GGC_H) gt-dbxout.h debug.o : debug.c debug.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) sdbout.o : sdbout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \ flags.h function.h $(EXPR_H) output.h hard-reg-set.h $(REGS_H) real.h \ - insn-config.h xcoffout.h c-pragma.h ggc.h $(TARGET_H) \ + insn-config.h xcoffout.h c-pragma.h $(GGC_H) $(TARGET_H) \ sdbout.h toplev.h $(TM_P_H) except.h debug.h langhooks.h gt-sdbout.h dwarfout.o : dwarfout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(RTL_H) dwarf.h flags.h insn-config.h reload.h output.h toplev.h $(TM_P_H) \ @@ -1480,7 +1483,7 @@ dwarf2out.o : dwarf2out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) hard-reg-set.h $(REGS_H) $(EXPR_H) libfuncs.h toplev.h dwarf2out.h varray.h \ $(GGC_H) except.h dwarf2asm.h $(TM_P_H) langhooks.h $(HASHTAB_H) gt-dwarf2out.h dwarf2asm.o : dwarf2asm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) flags.h $(RTL_H) \ - $(TREE_H) output.h dwarf2asm.h $(TM_P_H) $(GGC_H) + $(TREE_H) output.h dwarf2asm.h $(TM_P_H) $(GGC_H) gt-dwarf2asm.h vmsdbgout.o : vmsdbgout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(RTL_H) flags.h output.h vmsdbg.h debug.h langhooks.h function.h $(TARGET_H) xcoffout.o : xcoffout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \ @@ -1862,22 +1865,22 @@ s-preds: genpreds$(build_exeext) $(srcdir)/move-if-change $(SHELL) $(srcdir)/move-if-change tmp-preds.h tm-preds.h $(STAMP) s-preds -GTFILES = $(srcdir)/location.h $(srcdir)/coretypes.h \ - $(host_xm_file_list) $(tm_file_list) $(HASHTAB_H) \ +GTFILES = $(srcdir)/location.h $(srcdir)/coretypes.h $(srcdir)/cpplib.h \ + $(host_xm_file_list) $(tm_file_list) $(HASHTAB_H) $(SPLAY_TREE_H) \ $(srcdir)/bitmap.h $(srcdir)/function.h $(srcdir)/rtl.h $(srcdir)/optabs.h \ $(srcdir)/tree.h $(srcdir)/libfuncs.h $(srcdir)/hashtable.h $(srcdir)/real.h \ $(srcdir)/varray.h $(srcdir)/ssa.h $(srcdir)/insn-addr.h $(srcdir)/cselib.h \ + $(srcdir)/basic-block.h $(srcdir)/location.h \ $(srcdir)/c-common.h $(srcdir)/c-tree.h \ - $(srcdir)/basic-block.h \ $(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c \ - $(srcdir)/dwarf2out.c $(srcdir)/emit-rtl.c \ - $(srcdir)/except.c $(srcdir)/explow.c $(srcdir)/expr.c \ + $(srcdir)/dbxout.c $(srcdir)/dwarf2out.c $(srcdir)/dwarf2asm.c \ + $(srcdir)/emit-rtl.c $(srcdir)/except.c $(srcdir)/explow.c $(srcdir)/expr.c \ $(srcdir)/fold-const.c $(srcdir)/function.c \ $(srcdir)/gcse.c $(srcdir)/integrate.c $(srcdir)/lists.c $(srcdir)/optabs.c \ $(srcdir)/profile.c $(srcdir)/ra-build.c $(srcdir)/regclass.c \ $(srcdir)/reg-stack.c \ $(srcdir)/sdbout.c $(srcdir)/stmt.c $(srcdir)/stor-layout.c \ - $(srcdir)/tree.c $(srcdir)/varasm.c \ + $(srcdir)/stringpool.c $(srcdir)/tree.c $(srcdir)/varasm.c \ $(out_file) \ @all_gtfiles@ @@ -1891,9 +1894,9 @@ gt-integrate.h gt-stmt.h gt-tree.h gt-varasm.h gt-emit-rtl.h : s-gtype; @true gt-explow.h gt-stor-layout.h gt-regclass.h gt-lists.h : s-gtype; @true gt-alias.h gt-cselib.h gt-fold-const.h gt-gcse.h gt-profile.h : s-gtype; @true gt-expr.h gt-sdbout.h gt-optabs.h gt-bitmap.h gt-dwarf2out.h : s-gtype ; @true -gt-ra-build.h gt-reg-stack.h : s-gtype ; @true +gt-ra-build.h gt-reg-stack.h gt-dwarf2asm.h gt-dbxout.h : s-gtype ; @true gt-c-common.h gt-c-decl.h gt-c-parse.h gt-c-pragma.h : s-gtype; @true -gt-c-objc-common.h gtype-c.h gt-location.h : s-gtype ; @true +gt-c-objc-common.h gtype-c.h gt-location.h gt-stringpool.h : s-gtype ; @true gtyp-gen.h: Makefile echo "/* This file is machine generated. Do not edit. */" > tmp-gtyp.h @@ -2215,7 +2218,7 @@ PREPROCESSOR_DEFINES = \ LIBCPP_OBJS = cpplib.o cpplex.o cppmacro.o cppexp.o cppfiles.o cpptrad.o \ cpphash.o cpperror.o cppinit.o cppdefault.o cppmain.o \ - hashtable.o line-map.o mkdeps.o prefix.o mbchar.o + hashtable.o line-map.o mkdeps.o prefix.o mbchar.o cpppch.o LIBCPP_DEPS = $(CPPLIB_H) cpphash.h line-map.h hashtable.h intl.h \ $(OBSTACK_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) @@ -2238,6 +2241,7 @@ cpphash.o: cpphash.c $(LIBCPP_DEPS) cpptrad.o: cpptrad.c $(LIBCPP_DEPS) cppfiles.o: cppfiles.c $(LIBCPP_DEPS) $(SPLAY_TREE_H) mkdeps.h cppinit.o: cppinit.c $(LIBCPP_DEPS) cppdefault.h mkdeps.h prefix.h +cpppch.o: cpppch.c $(LIBCPP_DEPS) mkdeps.h cppdefault.o: cppdefault.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) cppdefault.h \ Makefile diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 6b435f5..0d06e9c 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,9 @@ +2003-01-09 Geoffrey Keating + + * gnat_rm.texi: Remove RCS version number. + + * ada-tree.h (union lang_tree_node): Add chain_next option. + 2003-01-09 Christian Cornelssen * Make-lang.in (ada.install-info, ada.install-common, diff --git a/gcc/ada/ada-tree.h b/gcc/ada/ada-tree.h index 53087a7..b1904a4 100644 --- a/gcc/ada/ada-tree.h +++ b/gcc/ada/ada-tree.h @@ -43,7 +43,8 @@ struct tree_loop_id GTY(()) /* The language-specific tree. */ union lang_tree_node - GTY((desc ("TREE_CODE (&%h.generic) == GNAT_LOOP_ID"))) + GTY((desc ("TREE_CODE (&%h.generic) == GNAT_LOOP_ID"), + chain_next ("(union lang_tree_node *)TREE_CHAIN (&%h.generic)"))) { union tree_node GTY ((tag ("0"), desc ("tree_node_structure (&%h)"))) diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi index dd43cf0..f9c78ce 100644 --- a/gcc/ada/gnat_rm.texi +++ b/gcc/ada/gnat_rm.texi @@ -8,8 +8,6 @@ @c o @c G N A T _ RM o @c o -@c $Revision: 1.9 $ -@c o @c Copyright (C) 1995-2002 Free Software Foundation o @c o @c o diff --git a/gcc/c-common.c b/gcc/c-common.c index 12cacab..84166c9 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -31,6 +31,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "c-pragma.h" #include "rtl.h" #include "ggc.h" +#include "varray.h" #include "expr.h" #include "c-common.h" #include "diagnostic.h" @@ -190,11 +191,20 @@ enum c_language_kind c_language; tree c_global_trees[CTI_MAX]; +/* Nonzero if we can read a PCH file now. */ + +int allow_pch = 1; + /* Switches common to the C front ends. */ /* Nonzero if prepreprocessing only. */ int flag_preprocess_only; +/* The file name to which we should write a precompiled header, or + NULL if no header will be written in this compile. */ + +const char *pch_file; + /* Nonzero if an ISO standard was selected. It rejects macros in the user's namespace. */ int flag_iso; diff --git a/gcc/c-common.h b/gcc/c-common.h index 4c60d29..3e97662 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -121,7 +121,7 @@ enum rid /* The elements of `ridpointers' are identifier nodes for the reserved type names and storage classes. It is indexed by a RID_... value. */ -extern tree *ridpointers; +extern GTY ((length ("(int)RID_MAX"))) tree *ridpointers; /* Standard named or nameless data types of the C compiler. */ @@ -177,7 +177,7 @@ enum c_tree_index struct c_common_identifier GTY(()) { struct tree_common common; - struct cpp_hashnode GTY ((skip (""))) node; + struct cpp_hashnode node; }; #define wchar_type_node c_global_trees[CTI_WCHAR_TYPE] @@ -360,13 +360,24 @@ struct c_lang_decl GTY(()) { extern c_language_kind c_language; +/* Nonzero if we can read a PCH file now. */ + +extern int allow_pch; + /* Switches common to the C front ends. */ /* Nonzero if prepreprocessing only. */ + extern int flag_preprocess_only; +/* The file name to which we should write a precompiled header, or + NULL if no header will be written in this compile. */ + +extern const char *pch_file; + /* Nonzero if an ISO standard was selected. It rejects macros in the user's namespace. */ + extern int flag_iso; /* Nonzero whenever Objective-C functionality is being used. */ @@ -374,6 +385,7 @@ extern int flag_objc; /* Nonzero if -undef was given. It suppresses target built-in macros and assertions. */ + extern int flag_undef; /* Nonzero means don't recognize the non-ANSI builtin functions. */ @@ -1253,4 +1265,14 @@ extern void dump_time_statistics PARAMS ((void)); extern int c_dump_tree PARAMS ((void *, tree)); +extern void pch_init PARAMS ((void)); +extern int c_common_valid_pch PARAMS ((cpp_reader *pfile, + const char *name, + int fd)); +extern void c_common_read_pch PARAMS ((cpp_reader *pfile, + const char *name, + int fd, + const char *orig)); +extern void c_common_write_pch PARAMS ((void)); + #endif /* ! GCC_C_COMMON_H */ diff --git a/gcc/c-decl.c b/gcc/c-decl.c index fde8c48..e3d07aa 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -3226,6 +3226,8 @@ clear_parm_order () current_binding_level->parm_order = NULL_TREE; } +static GTY(()) int compound_literal_number; + /* Build a COMPOUND_LITERAL_EXPR. TYPE is the type given in the compound literal, which may be an incomplete array type completed by the initializer; INIT is a CONSTRUCTOR that initializes the compound @@ -3273,10 +3275,10 @@ build_compound_literal (type, init) /* This decl needs a name for the assembler output. We also need a unique suffix to be added to the name. */ char *name; - extern int var_labelno; - ASM_FORMAT_PRIVATE_NAME (name, "__compound_literal", var_labelno); - var_labelno++; + ASM_FORMAT_PRIVATE_NAME (name, "__compound_literal", + compound_literal_number); + compound_literal_number++; DECL_NAME (decl) = get_identifier (name); DECL_DEFER_OUTPUT (decl) = 1; DECL_COMDAT (decl) = 1; diff --git a/gcc/c-lex.c b/gcc/c-lex.c index 5507e63..a689ccab 100644 --- a/gcc/c-lex.c +++ b/gcc/c-lex.c @@ -124,6 +124,8 @@ init_c_lex (filename) cb->ident = cb_ident; cb->file_change = cb_file_change; cb->def_pragma = cb_def_pragma; + cb->valid_pch = c_common_valid_pch; + cb->read_pch = c_common_read_pch; /* Set the debug callbacks if we can use them. */ if (debug_info_level == DINFO_LEVEL_VERBOSE @@ -158,6 +160,8 @@ c_common_parse_file (set_yydebug) (*debug_hooks->start_source_file) (lineno, input_filename); cpp_finish_options (parse_in); + pch_init(); + yyparse (); free_parser_stacks (); } diff --git a/gcc/c-objc-common.c b/gcc/c-objc-common.c index 7d54d7a..c91e635 100644 --- a/gcc/c-objc-common.c +++ b/gcc/c-objc-common.c @@ -1,5 +1,5 @@ /* Some code common to C and ObjC front ends. - Copyright (C) 2001 Free Software Foundation, Inc. + Copyright (C) 2001, 2002 Free Software Foundation, Inc. This file is part of GCC. @@ -358,6 +358,9 @@ finish_cdtor (body) void c_objc_common_finish_file () { + if (pch_file) + c_common_write_pch (); + expand_deferred_fns (); if (static_ctors) diff --git a/gcc/c-opts.c b/gcc/c-opts.c index 85ed5f3..5270d62 100644 --- a/gcc/c-opts.c +++ b/gcc/c-opts.c @@ -112,6 +112,7 @@ static void sanitize_cpp_opts PARAMS ((void)); #define COMMAND_LINE_OPTIONS \ OPT("-help", CL_ALL, OPT__help) \ + OPT("-output-pch=", CL_ALL | CL_ARG, OPT__output_pch) \ OPT("C", CL_ALL, OPT_C) \ OPT("CC", CL_ALL, OPT_CC) \ OPT("E", CL_ALL, OPT_E) \ @@ -154,6 +155,7 @@ static void sanitize_cpp_opts PARAMS ((void)); OPT("Wimplicit-function-declaration", CL_C, OPT_Wimplicit_function_decl) \ OPT("Wimplicit-int", CL_C, OPT_Wimplicit_int) \ OPT("Wimport", CL_ALL, OPT_Wimport) \ + OPT("Winvalid-pch", CL_ALL, OPT_Winvalid_pch) \ OPT("Wlong-long", CL_ALL, OPT_Wlong_long) \ OPT("Wmain", CL_C, OPT_Wmain) \ OPT("Wmissing-braces", CL_ALL, OPT_Wmissing_braces) \ @@ -231,6 +233,7 @@ static void sanitize_cpp_opts PARAMS ((void)); OPT("fnonnull-objects", CL_CXX, OPT_fnonnull_objects) \ OPT("foperator-names", CL_CXX, OPT_foperator_names) \ OPT("foptional-diags", CL_CXX, OPT_foptional_diags) \ + OPT("fpch-deps", CL_ALL, OPT_fpch_deps) \ OPT("fpermissive", CL_CXX, OPT_fpermissive) \ OPT("fpreprocessed", CL_ALL, OPT_fpreprocessed) \ OPT("frepo", CL_CXX, OPT_frepo) \ @@ -343,6 +346,7 @@ missing_arg (opt_index) switch (cl_options[opt_index].opt_code) { + case OPT__output_pch: case OPT_Wformat_eq: case OPT_d: case OPT_fabi_version: @@ -627,6 +631,10 @@ c_common_decode_option (argc, argv) print_help (); break; + case OPT__output_pch: + pch_file = arg; + break; + case OPT_C: cpp_opts->discard_comments = 0; break; @@ -832,6 +840,10 @@ c_common_decode_option (argc, argv) cpp_opts->warn_import = on; break; + case OPT_Winvalid_pch: + cpp_opts->warn_invalid_pch = on; + break; + case OPT_Wlong_long: warn_long_long = on; break; @@ -1178,6 +1190,10 @@ c_common_decode_option (argc, argv) flag_optional_diags = on; break; + case OPT_fpch_deps: + cpp_opts->restore_pch_deps = on; + break; + case OPT_fpermissive: flag_permissive = on; break; diff --git a/gcc/c-parse.in b/gcc/c-parse.in index 70dfe90..72ca4fe 100644 --- a/gcc/c-parse.in +++ b/gcc/c-parse.in @@ -48,6 +48,7 @@ end ifc #include "c-pragma.h" /* For YYDEBUG definition, and parse_in. */ #include "c-tree.h" #include "flags.h" +#include "varray.h" #include "output.h" #include "toplev.h" #include "ggc.h" @@ -3555,10 +3556,7 @@ init_reswords () if (!flag_objc) mask |= D_OBJC; - /* It is not necessary to register ridpointers as a GC root, because - all the trees it points to are permanently interned in the - get_identifier hash anyway. */ - ridpointers = (tree *) xcalloc ((int) RID_MAX, sizeof (tree)); + ridpointers = (tree *) ggc_calloc ((int) RID_MAX, sizeof (tree)); for (i = 0; i < N_reswords; i++) { /* If a keyword is disabled, do not enter it into the table diff --git a/gcc/c-pch.c b/gcc/c-pch.c new file mode 100644 index 0000000..616e002 --- /dev/null +++ b/gcc/c-pch.c @@ -0,0 +1,226 @@ +/* Precompiled header implementation for the C languages. + Copyright (C) 2000, 2002 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the 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 of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "cpplib.h" +#include "tree.h" +#include "c-common.h" +#include "output.h" +#include "toplev.h" +#include "debug.h" +#include "c-pragma.h" +#include "ggc.h" + +struct c_pch_header +{ + unsigned long asm_size; +}; + +static const char pch_ident[8] = "gpchC010"; + +static FILE *pch_outfile; + +extern char *asm_file_name; +static off_t asm_file_startpos; + +void +pch_init () +{ + FILE *f; + + if (pch_file) + { + /* We're precompiling a header file, so when it's actually used, + it'll be at least one level deep. */ + (*debug_hooks->start_source_file) (lineno, input_filename); + + f = fopen (pch_file, "w+b"); + if (f == NULL) + fatal_io_error ("can't open %s", pch_file); + pch_outfile = f; + + if (fwrite (pch_ident, sizeof (pch_ident), 1, f) != 1) + fatal_io_error ("can't write to %s", pch_file); + + /* We need to be able to re-read the output. */ + /* The driver always provides a valid -o option. */ + if (asm_file_name == NULL + || strcmp (asm_file_name, "-") == 0) + fatal_error ("`%s' is not a valid output file", asm_file_name); + + asm_file_startpos = ftello (asm_out_file); + + cpp_save_state (parse_in, f); + } +} + +void +c_common_write_pch () +{ + char *buf; + off_t asm_file_end; + off_t written; + struct c_pch_header h; + + cpp_write_pch_deps (parse_in, pch_outfile); + + asm_file_end = ftello (asm_out_file); + h.asm_size = asm_file_end - asm_file_startpos; + + if (fwrite (&h, sizeof (h), 1, pch_outfile) != 1) + fatal_io_error ("can't write %s", pch_file); + + buf = xmalloc (16384); + fflush (asm_out_file); + + if (fseeko (asm_out_file, asm_file_startpos, SEEK_SET) != 0) + fatal_io_error ("can't seek in %s", asm_file_name); + + for (written = asm_file_startpos; written < asm_file_end; ) + { + off_t size = asm_file_end - written; + if (size > 16384) + size = 16384; + if (fread (buf, size, 1, asm_out_file) != 1) + fatal_io_error ("can't read %s", asm_file_name); + if (fwrite (buf, size, 1, pch_outfile) != 1) + fatal_io_error ("can't write %s", pch_file); + written += size; + } + free (buf); + + gt_pch_save (pch_outfile); + cpp_write_pch_state (parse_in, pch_outfile); + + fclose (pch_outfile); +} + +int +c_common_valid_pch (pfile, name, fd) + cpp_reader *pfile; + const char *name; + int fd; +{ + int sizeread; + int result; + char ident[sizeof (pch_ident)]; + + if (! allow_pch) + return 2; + + /* Perform a quick test of whether this is a valid + precompiled header for C. */ + + sizeread = read (fd, ident, sizeof (pch_ident)); + if (sizeread == -1) + { + fatal_io_error ("can't read %s", name); + return 2; + } + else if (sizeread != sizeof (pch_ident)) + return 2; + + if (memcmp (ident, pch_ident, sizeof (pch_ident)) != 0) + { + if (cpp_get_options (pfile)->warn_invalid_pch) + { + if (memcmp (ident, pch_ident, 5) == 0) + /* It's a PCH, for the right language, but has the wrong version. + */ + cpp_error (pfile, DL_WARNING, + "%s: not compatible with this GCC version", name); + else if (memcmp (ident, pch_ident, 4) == 0) + /* It's a PCH for the wrong language. */ + cpp_error (pfile, DL_WARNING, "%s: not for C language", name); + else + /* Not any kind of PCH. */ + cpp_error (pfile, DL_WARNING, "%s: not a PCH file", name); + } + return 2; + } + + /* Check the preprocessor macros are the same as when the PCH was + generated. */ + + result = cpp_valid_state (pfile, name, fd); + if (result == -1) + return 2; + else + return result == 0; +} + +void +c_common_read_pch (pfile, name, fd, orig_name) + cpp_reader *pfile; + const char *name; + int fd; + const char *orig_name; +{ + FILE *f; + struct c_pch_header h; + char *buf; + unsigned long written; + struct save_macro_data *smd; + + /* Before we wrote the file, we started a source file, so we have to start + one here to match. */ + (*debug_hooks->start_source_file) (lineno, orig_name); + + f = fdopen (fd, "rb"); + if (f == NULL) + { + cpp_errno (pfile, DL_ERROR, "calling fdopen"); + return; + } + + allow_pch = 0; + + if (fread (&h, sizeof (h), 1, f) != 1) + { + cpp_errno (pfile, DL_ERROR, "reading"); + return; + } + + buf = xmalloc (16384); + for (written = 0; written < h.asm_size; ) + { + off_t size = h.asm_size - written; + if (size > 16384) + size = 16384; + if (fread (buf, size, 1, f) != 1 + || fwrite (buf, size, 1, asm_out_file) != 1) + cpp_errno (pfile, DL_ERROR, "reading"); + written += size; + } + free (buf); + + cpp_prepare_state (pfile, &smd); + + gt_pch_restore (f); + + if (cpp_read_state (pfile, name, f, smd) != 0) + return; + + fclose (f); + + (*debug_hooks->end_source_file) (lineno); +} diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index ce0810d..dbbf110 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -50,6 +50,7 @@ Boston, MA 02111-1307, USA. */ #include "target-def.h" #include "debug.h" #include "langhooks.h" +#include /* Specify which cpu to schedule for. */ @@ -9023,6 +9024,20 @@ alpha_elf_select_rtx_section (mode, x, align) #endif /* OBJECT_FORMAT_ELF */ +/* Structure to collect function names for final output + in link section. */ + +enum links_kind {KIND_UNUSED, KIND_LOCAL, KIND_EXTERN}; + +struct alpha_links GTY(()) +{ + rtx linkage; + enum links_kind kind; +}; + +static GTY ((param1_is (char *), param2_is (struct alpha_links *))) + splay_tree alpha_links; + #if TARGET_ABI_OPEN_VMS /* Return the VMS argument type corresponding to MODE. */ @@ -9058,26 +9073,6 @@ alpha_arg_info_reg_val (cum) return GEN_INT (regval); } -/* Protect alpha_links from garbage collection. */ - -static int -mark_alpha_links_node (node, data) - splay_tree_node node; - void *data ATTRIBUTE_UNUSED; -{ - struct alpha_links *links = (struct alpha_links *) node->value; - ggc_mark_rtx (links->linkage); - return 0; -} - -static void -mark_alpha_links (ptr) - void *ptr; -{ - splay_tree tree = *(splay_tree *) ptr; - splay_tree_foreach (tree, mark_alpha_links_node, NULL); -} - /* Make (or fake) .linkage entry for function call. IS_LOCAL is 0 if name is used in call, 1 if name is used in definition. @@ -9139,16 +9134,11 @@ alpha_need_linkage (name, is_local) } else { - alpha_links_tree = splay_tree_new - ((splay_tree_compare_fn) strcmp, - (splay_tree_delete_key_fn) free, - (splay_tree_delete_key_fn) free); - - ggc_add_root (&alpha_links_tree, 1, 1, mark_alpha_links); + alpha_links = splay_tree_new_ggc ((splay_tree_compare_fn) strcmp); } - al = (struct alpha_links *) xmalloc (sizeof (struct alpha_links)); - name = xstrdup (name); + al = (struct alpha_links *) ggc_alloc (sizeof (struct alpha_links)); + name = ggc_strdup (name); /* Assume external if no definition. */ al->lkind = (is_local ? KIND_UNUSED : KIND_EXTERN); diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c index a7dfe59..bce6d11 100644 --- a/gcc/config/darwin.c +++ b/gcc/config/darwin.c @@ -223,7 +223,7 @@ machopic_define_name (name) static char function_base[32]; -static int current_pic_label_num; +static GTY(()) int current_pic_label_num; const char * machopic_function_base_name () diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 6112737..7880cd5 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -168,7 +168,6 @@ struct builtin_description }; static bool rs6000_function_ok_for_sibcall PARAMS ((tree, tree)); -static void rs6000_add_gc_roots PARAMS ((void)); static int num_insns_constant_wide PARAMS ((HOST_WIDE_INT)); static void validate_condition_mode PARAMS ((enum rtx_code, enum machine_mode)); @@ -183,8 +182,6 @@ static void rs6000_emit_allocate_stack PARAMS ((HOST_WIDE_INT, int)); static unsigned rs6000_hash_constant PARAMS ((rtx)); static unsigned toc_hash_function PARAMS ((const void *)); static int toc_hash_eq PARAMS ((const void *, const void *)); -static int toc_hash_mark_entry PARAMS ((void **, void *)); -static void toc_hash_mark_table PARAMS ((void *)); static int constant_pool_expr_1 PARAMS ((rtx, int *, int *)); static struct machine_function * rs6000_init_machine_status PARAMS ((void)); static bool rs6000_assemble_integer PARAMS ((rtx, unsigned int, int)); @@ -267,6 +264,19 @@ static void is_altivec_return_reg PARAMS ((rtx, void *)); static rtx generate_set_vrsave PARAMS ((rtx, rs6000_stack_t *, int)); static void altivec_frame_fixup PARAMS ((rtx, rtx, HOST_WIDE_INT)); static int easy_vector_constant PARAMS ((rtx)); + +/* Hash table stuff for keeping track of TOC entries. */ + +struct toc_hash_struct GTY(()) +{ + /* `key' will satisfy CONSTANT_P; in fact, it will satisfy + ASM_OUTPUT_SPECIAL_POOL_ENTRY_P. */ + rtx key; + enum machine_mode key_mode; + int labelno; +}; + +static GTY ((param_is (struct toc_hash_struct))) htab_t toc_hash_table; /* Default register names. */ char rs6000_reg_names[][8] = @@ -708,9 +718,6 @@ rs6000_override_options (default_cpu) && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)) real_format_for_mode[TFmode - QFmode] = &ibm_extended_format; - /* Register global variables with the garbage collector. */ - rs6000_add_gc_roots (); - /* Allocate an alias set for register saves & restores from stack. */ rs6000_sr_alias_set = new_alias_set (); @@ -11457,19 +11464,6 @@ rs6000_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function) */ -/* Hash table stuff for keeping track of TOC entries. */ - -struct toc_hash_struct -{ - /* `key' will satisfy CONSTANT_P; in fact, it will satisfy - ASM_OUTPUT_SPECIAL_POOL_ENTRY_P. */ - rtx key; - enum machine_mode key_mode; - int labelno; -}; - -static htab_t toc_hash_table; - /* Hash functions for the hash table. */ static unsigned @@ -11570,39 +11564,6 @@ toc_hash_eq (h1, h2) return rtx_equal_p (r1, r2); } -/* Mark the hash table-entry HASH_ENTRY. */ - -static int -toc_hash_mark_entry (hash_slot, unused) - void ** hash_slot; - void * unused ATTRIBUTE_UNUSED; -{ - const struct toc_hash_struct * hash_entry = - *(const struct toc_hash_struct **) hash_slot; - rtx r = hash_entry->key; - ggc_set_mark (hash_entry); - /* For CODE_LABELS, we don't want to drag in the whole insn chain... */ - if (GET_CODE (r) == LABEL_REF) - { - ggc_set_mark (r); - ggc_set_mark (XEXP (r, 0)); - } - else - ggc_mark_rtx (r); - return 1; -} - -/* Mark all the elements of the TOC hash-table *HT. */ - -static void -toc_hash_mark_table (vht) - void *vht; -{ - htab_t *ht = vht; - - htab_traverse (*ht, toc_hash_mark_entry, (void *)0); -} - /* These are the names given by the C++ front-end to vtables, and vtable-like objects. Ideally, this logic should not be here; instead, there should be some programmatic way of inquiring as @@ -11656,12 +11617,19 @@ output_toc (file, x, labelno, mode) /* When the linker won't eliminate them, don't output duplicate TOC entries (this happens on AIX if there is any kind of TOC, - and on SVR4 under -fPIC or -mrelocatable). */ - if (TARGET_TOC) + and on SVR4 under -fPIC or -mrelocatable). Don't do this for + CODE_LABELs. */ + if (TARGET_TOC && GET_CODE (x) != LABEL_REF) { struct toc_hash_struct *h; void * * found; + /* Create toc_hash_table. This can't be done at OVERRIDE_OPTIONS + time because GGC is not initialised at that point. */ + if (toc_hash_table == NULL) + toc_hash_table = htab_create_ggc (1021, toc_hash_function, + toc_hash_eq, NULL); + h = ggc_alloc (sizeof (*h)); h->key = x; h->key_mode = mode; @@ -12685,17 +12653,6 @@ rs6000_fatal_bad_address (op) fatal_insn ("bad address", op); } -/* Called to register all of our global variables with the garbage - collector. */ - -static void -rs6000_add_gc_roots () -{ - toc_hash_table = htab_create (1021, toc_hash_function, toc_hash_eq, NULL); - ggc_add_root (&toc_hash_table, 1, sizeof (toc_hash_table), - toc_hash_mark_table); -} - #if TARGET_MACHO #if 0 @@ -13312,3 +13269,4 @@ rs6000_memory_move_cost (mode, class, in) return 4 + rs6000_register_move_cost (mode, class, GENERAL_REGS); } +#include "gt-rs6000.h" diff --git a/gcc/config/rs6000/t-rs6000 b/gcc/config/rs6000/t-rs6000 index 805e15d..c2a7848 100644 --- a/gcc/config/rs6000/t-rs6000 +++ b/gcc/config/rs6000/t-rs6000 @@ -1,14 +1,17 @@ # General rules that all rs6000/ targets must have. +gt-rs6000.h: s-gtype ; @true + rs6000.o: $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(RTL_H) $(REGS_H) hard-reg-set.h \ real.h insn-config.h conditions.h insn-attr.h flags.h $(RECOG_H) \ $(OBSTACK_H) $(TREE_H) $(EXPR_H) $(OPTABS_H) except.h function.h \ output.h $(BASIC_BLOCK_H) $(INTEGRATE_H) toplev.h $(GGC_H) $(HASHTAB_H) \ - $(TM_P_H) $(TARGET_H) $(TARGET_DEF_H) langhooks.h reload.h + $(TM_P_H) $(TARGET_H) $(TARGET_DEF_H) langhooks.h reload.h gt-rs6000.h rs6000-c.o: $(srcdir)/config/rs6000/rs6000-c.c \ $(srcdir)/config/rs6000/rs6000-protos.h \ $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(CPPLIB_H) \ $(TM_P_H) c-pragma.h errors.h coretypes.h $(TM_H) $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/rs6000/rs6000-c.c + diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2970abb..fb53043 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,93 @@ +2003-01-09 Geoffrey Keating + + Merge from pch-branch: + + 2003-01-09 Geoffrey Keating + + Merge to tag pch-merge-20030102: + + * semantics.c (finish_translation_unit): Don't call finish_file. + * parser.c: Don't include ggc.h. + (cp_lexer_new_main): Rename from cp_lexer_new, only create main lexer, + read first token here. Don't allow PCH files after the first + token is read. + (cp_lexer_new_from_tokens): Duplicate functionality from cp_lexer_new. + (cp_lexer_get_preprocessor_token): Allow LEXER to be NULL. + (cp_parser_new): Call cp_lexer_new_main before allocating GCed memory. + (cp_parser_late_parsing_for_member): Don't duplicate call to + cp_lexer_set_source_position_from_token. + (cp_parser_late_parsing_default_args): Likewise. + (yyparse): Call finish_file after clearing the_parser. + + 2002-12-11 Geoffrey Keating + + * Make-lang.in: Remove $(GGC_H) from all dependencies. + (CXX_TREE_H): Add $(GGC_H). + * class.c: Don't include ggc.h. + (field_decl_cmp): Make parameters be 'const void *' to match qsort. + (method_name_cmp): Likewise. + (resort_data): New variable. + (resort_field_decl_cmp): New. + (resort_method_name_cmp): New. + (resort_sorted_fields): New. + (resort_type_method_vec): New. + (finish_struct_methods): Delete cast. + (finish_struct_1): Delete cast. + * cp-tree.h: Include ggc.h. + (struct lang_type_class): Add reorder attribute to field `methods'. + (union lang_decl_u3): Add reorder attribute to field `sorted_fields'. + (resort_sorted_fields): New prototype. + (resort_type_method_vec): New prototype. + * call.c: Don't include ggc.h. + * decl.c: Likewise. + * decl2.c: Likewise. + * init.c: Likewise. + * lex.c: Likewise. + * method.c: Likewise. + * optimize.c: Likewise. + * parse.y: Likewise. + * pt.c: Likewise. + * repo.c: Likewise. + * search.c: Likewise. + * semantics.c: Likewise. + * spew.c: Likewise. + * tree.c: Likewise. + + * lang-specs.h: Remove comment. + + 2002-12-03 Geoffrey Keating + + * cp-tree.h (struct operator_name_info_t): Mark for GTY machinery. + (operator_name_info): Mark to be saved for PCH, specify size. + (assignment_operator_name_info): Likewise. + + 2002-11-19 Geoffrey Keating + + * decl.c (anon_cnt): Mark to be saved for PCH. + + 2002-10-25 Geoffrey Keating + + * lex.c (init_reswords): Delete now-untrue comment. + Allocate ridpointers using GGC. + + 2002-10-04 Geoffrey Keating + + * cp-tree.h (union lang_decl_u2): Add tags to all fields. + + * g++spec.c (lang_specific_driver): Don't include standard + libraries in `added'. + + 2002-08-27 Geoffrey Keating + + * decl2.c (finish_file): Call c_common_write_pch. + * Make-lang.in (CXX_C_OBJS): Add c-pch.o. + + 2002-08-17 Geoffrey Keating + + * g++spec.c (lang_specific_driver): Treat .h files as C++ header + files when using g++. + * lang-specs.h: Handle compiling C++ header files. + 2003-01-09 Jakub Jelinek * decl.c (start_decl): Only check DECL_THREAD_LOCAL for VAR_DECLs. diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index b54e3ba..347b71a 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -1,5 +1,5 @@ # Top level -*- makefile -*- fragment for GNU C++. -# Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002 +# Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003 # Free Software Foundation, Inc. #This file is part of GCC. @@ -79,7 +79,7 @@ g++-cross$(exeext): g++$(exeext) # The compiler itself. # Shared with C front end: CXX_C_OBJS = attribs.o c-common.o c-format.o c-pragma.o c-semantics.o c-lex.o \ - c-dump.o $(CXX_TARGET_OBJS) c-pretty-print.o c-opts.o + c-dump.o $(CXX_TARGET_OBJS) c-pretty-print.o c-opts.o c-pch.o # Language-specific object files. CXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \ @@ -210,34 +210,35 @@ c++.stage4: stage4-start # .o: .h dependencies. CXX_TREE_H = $(TREE_H) cp/cp-tree.h c-common.h cp/cp-tree.def c-common.def \ function.h varray.h $(SYSTEM_H) coretypes.h $(CONFIG_H) $(TARGET_H) \ + $(GGC_H) \ $(srcdir)/../include/hashtab.h $(srcdir)/../include/splay-tree.h cp/lex.o: cp/lex.c $(CXX_TREE_H) $(TM_H) flags.h cp/lex.h \ - c-pragma.h toplev.h output.h mbchar.h $(GGC_H) input.h diagnostic.h \ + c-pragma.h toplev.h output.h mbchar.h input.h diagnostic.h \ cp/operators.def $(TM_P_H) cp/cp-lang.o: cp/cp-lang.c $(CXX_TREE_H) $(TM_H) toplev.h langhooks.h \ $(LANGHOOKS_DEF_H) c-common.h cp/decl.o: cp/decl.c $(CXX_TREE_H) $(TM_H) flags.h cp/lex.h cp/decl.h stack.h \ - output.h $(EXPR_H) except.h toplev.h $(HASHTAB_H) $(GGC_H) $(RTL_H) \ + output.h $(EXPR_H) except.h toplev.h $(HASHTAB_H) $(RTL_H) \ cp/operators.def $(TM_P_H) tree-inline.h diagnostic.h c-pragma.h \ debug.h gt-cp-decl.h gtype-cp.h cp/decl2.o: cp/decl2.c $(CXX_TREE_H) $(TM_H) flags.h cp/lex.h cp/decl.h $(EXPR_H) \ - output.h except.h toplev.h $(GGC_H) $(RTL_H) c-common.h gt-cp-decl2.h + output.h except.h toplev.h $(RTL_H) c-common.h gt-cp-decl2.h cp/typeck2.o: cp/typeck2.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h output.h $(TM_P_H) \ diagnostic.h cp/typeck.o: cp/typeck.c $(CXX_TREE_H) $(TM_H) flags.h $(RTL_H) $(EXPR_H) toplev.h \ diagnostic.h cp/class.o: cp/class.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h $(RTL_H) $(TARGET_H) cp/call.o: cp/call.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h $(RTL_H) $(EXPR_H) \ - $(GGC_H) diagnostic.h gt-cp-call.h + diagnostic.h gt-cp-call.h cp/friend.o: cp/friend.c $(CXX_TREE_H) $(TM_H) flags.h $(RTL_H) toplev.h $(EXPR_H) cp/init.o: cp/init.c $(CXX_TREE_H) $(TM_H) flags.h $(RTL_H) $(EXPR_H) toplev.h \ - $(GGC_H) except.h -cp/method.o: cp/method.c $(CXX_TREE_H) $(TM_H) toplev.h $(GGC_H) $(RTL_H) $(EXPR_H) \ + except.h +cp/method.o: cp/method.c $(CXX_TREE_H) $(TM_H) toplev.h $(RTL_H) $(EXPR_H) \ $(TM_P_H) $(TARGET_H) cp/cvt.o: cp/cvt.c $(CXX_TREE_H) $(TM_H) cp/decl.h flags.h toplev.h convert.h cp/search.o: cp/search.c $(CXX_TREE_H) $(TM_H) stack.h flags.h toplev.h $(RTL_H) -cp/tree.o: cp/tree.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h $(GGC_H) $(RTL_H) \ +cp/tree.o: cp/tree.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h $(RTL_H) \ insn-config.h integrate.h tree-inline.h real.h gt-cp-tree.h $(TARGET_H) cp/ptree.o: cp/ptree.c $(CXX_TREE_H) $(TM_H) cp/rtti.o: cp/rtti.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h @@ -246,13 +247,13 @@ cp/except.o: cp/except.c $(CXX_TREE_H) $(TM_H) flags.h $(RTL_H) except.h toplev. cp/expr.o: cp/expr.c $(CXX_TREE_H) $(TM_H) $(RTL_H) flags.h $(EXPR_H) toplev.h \ except.h $(TM_P_H) cp/pt.o: cp/pt.c $(CXX_TREE_H) $(TM_H) cp/decl.h cp/lex.h \ - toplev.h $(GGC_H) $(RTL_H) except.h tree-inline.h gt-cp-pt.h + toplev.h $(RTL_H) except.h tree-inline.h gt-cp-pt.h cp/error.o: cp/error.c $(CXX_TREE_H) $(TM_H) toplev.h diagnostic.h flags.h real.h \ $(LANGHOOKS_DEF_H) -cp/repo.o: cp/repo.c $(CXX_TREE_H) $(TM_H) toplev.h $(GGC_H) diagnostic.h \ +cp/repo.o: cp/repo.c $(CXX_TREE_H) $(TM_H) toplev.h diagnostic.h \ gt-cp-repo.h cp/semantics.o: cp/semantics.c $(CXX_TREE_H) $(TM_H) cp/lex.h except.h toplev.h \ - flags.h $(GGC_H) debug.h output.h $(RTL_H) $(TIMEVAR_H) $(EXPR_H) \ + flags.h debug.h output.h $(RTL_H) $(TIMEVAR_H) $(EXPR_H) \ tree-inline.h cp/dump.o: cp/dump.c $(CXX_TREE_H) $(TM_H) tree-dump.h cp/optimize.o: cp/optimize.c $(CXX_TREE_H) $(TM_H) rtl.h integrate.h insn-config.h \ diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 00458c0..cd93f7b 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -35,7 +35,6 @@ Boston, MA 02111-1307, USA. */ #include "rtl.h" #include "toplev.h" #include "expr.h" -#include "ggc.h" #include "diagnostic.h" extern int inhibit_warnings; diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 845ca19..bace3f4 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -33,7 +33,6 @@ Boston, MA 02111-1307, USA. */ #include "rtl.h" #include "output.h" #include "toplev.h" -#include "ggc.h" #include "lex.h" #include "target.h" @@ -125,8 +124,10 @@ static tree modify_all_vtables PARAMS ((tree, tree)); static void determine_primary_base PARAMS ((tree)); static void finish_struct_methods PARAMS ((tree)); static void maybe_warn_about_overly_private_class PARAMS ((tree)); -static int field_decl_cmp PARAMS ((const tree *, const tree *)); -static int method_name_cmp PARAMS ((const tree *, const tree *)); +static int field_decl_cmp PARAMS ((const void *, const void *)); +static int resort_field_decl_cmp PARAMS ((const void *, const void *)); +static int method_name_cmp PARAMS ((const void *, const void *)); +static int resort_method_name_cmp PARAMS ((const void *, const void *)); static void add_implicitly_declared_members PARAMS ((tree, int, int, int)); static tree fixed_type_or_null PARAMS ((tree, int *, int *)); static tree resolve_address_of_overloaded_function PARAMS ((tree, tree, int, @@ -1449,7 +1450,8 @@ mark_primary_virtual_base (base_binfo, type) base, then BINFO has no primary base in this graph. Called from mark_primary_bases. DATA is the most derived type. */ -static tree dfs_unshared_virtual_bases (binfo, data) +static tree +dfs_unshared_virtual_bases (binfo, data) tree binfo; void *data; { @@ -1923,9 +1925,11 @@ maybe_warn_about_overly_private_class (t) /* Function to help qsort sort FIELD_DECLs by name order. */ static int -field_decl_cmp (x, y) - const tree *x, *y; +field_decl_cmp (x_p, y_p) + const void *x_p, *y_p; { + const tree *const x = x_p; + const tree *const y = y_p; if (DECL_NAME (*x) == DECL_NAME (*y)) /* A nontype is "greater" than a type. */ return DECL_DECLARES_TYPE_P (*y) - DECL_DECLARES_TYPE_P (*x); @@ -1938,12 +1942,64 @@ field_decl_cmp (x, y) return 1; } +static struct { + gt_pointer_operator new_value; + void *cookie; +} resort_data; + +/* This routine compares two fields like field_decl_cmp but using the + pointer operator in resort_data. */ + +static int +resort_field_decl_cmp (x_p, y_p) + const void *x_p, *y_p; +{ + const tree *const x = x_p; + const tree *const y = y_p; + + if (DECL_NAME (*x) == DECL_NAME (*y)) + /* A nontype is "greater" than a type. */ + return DECL_DECLARES_TYPE_P (*y) - DECL_DECLARES_TYPE_P (*x); + if (DECL_NAME (*x) == NULL_TREE) + return -1; + if (DECL_NAME (*y) == NULL_TREE) + return 1; + { + tree d1 = DECL_NAME (*x); + tree d2 = DECL_NAME (*y); + resort_data.new_value (&d1, resort_data.cookie); + resort_data.new_value (&d2, resort_data.cookie); + if (d1 < d2) + return -1; + } + return 1; +} + +/* Resort DECL_SORTED_FIELDS because pointers have been reordered. */ + +void +resort_sorted_fields (obj, orig_obj, new_value, cookie) + void *obj; + void *orig_obj; + gt_pointer_operator new_value; + void *cookie; +{ + tree sf = obj; + resort_data.new_value = new_value; + resort_data.cookie = cookie; + qsort (&TREE_VEC_ELT (sf, 0), TREE_VEC_LENGTH (sf), sizeof (tree), + resort_field_decl_cmp); +} + /* Comparison function to compare two TYPE_METHOD_VEC entries by name. */ static int -method_name_cmp (m1, m2) - const tree *m1, *m2; +method_name_cmp (m1_p, m2_p) + const void *m1_p, *m2_p; { + const tree *const m1 = m1_p; + const tree *const m2 = m2_p; + if (*m1 == NULL_TREE && *m2 == NULL_TREE) return 0; if (*m1 == NULL_TREE) @@ -1955,6 +2011,63 @@ method_name_cmp (m1, m2) return 1; } +/* This routine compares two fields like method_name_cmp but using the + pointer operator in resort_field_decl_data. */ + +static int +resort_method_name_cmp (m1_p, m2_p) + const void *m1_p, *m2_p; +{ + const tree *const m1 = m1_p; + const tree *const m2 = m2_p; + if (*m1 == NULL_TREE && *m2 == NULL_TREE) + return 0; + if (*m1 == NULL_TREE) + return -1; + if (*m2 == NULL_TREE) + return 1; + { + tree d1 = DECL_NAME (OVL_CURRENT (*m1)); + tree d2 = DECL_NAME (OVL_CURRENT (*m2)); + resort_data.new_value (&d1, resort_data.cookie); + resort_data.new_value (&d2, resort_data.cookie); + if (d1 < d2) + return -1; + } + return 1; +} + +/* Resort TYPE_METHOD_VEC because pointers have been reordered. */ + +void +resort_type_method_vec (obj, orig_obj, new_value, cookie) + void *obj; + void *orig_obj; + gt_pointer_operator new_value; + void *cookie; +{ + tree method_vec = obj; + int len = TREE_VEC_LENGTH (method_vec); + int slot; + + /* The type conversion ops have to live at the front of the vec, so we + can't sort them. */ + for (slot = 2; slot < len; ++slot) + { + tree fn = TREE_VEC_ELT (method_vec, slot); + + if (!DECL_CONV_FN_P (OVL_CURRENT (fn))) + break; + } + if (len - slot > 1) + { + resort_data.new_value = new_value; + resort_data.cookie = cookie; + qsort (&TREE_VEC_ELT (method_vec, slot), len - slot, sizeof (tree), + resort_method_name_cmp); + } +} + /* Warn about duplicate methods in fn_fields. Also compact method lists so that lookup can be made faster. @@ -2025,7 +2138,7 @@ finish_struct_methods (t) } if (len - slot > 1) qsort (&TREE_VEC_ELT (method_vec, slot), len-slot, sizeof (tree), - (int (*)(const void *, const void *))method_name_cmp); + method_name_cmp); } /* Emit error when a duplicate definition of a type is seen. Patch up. */ @@ -5418,7 +5531,7 @@ finish_struct_1 (t) tree field_vec = make_tree_vec (n_fields); add_fields_to_vec (TYPE_FIELDS (t), field_vec, 0); qsort (&TREE_VEC_ELT (field_vec, 0), n_fields, sizeof (tree), - (int (*)(const void *, const void *))field_decl_cmp); + field_decl_cmp); if (! DECL_LANG_SPECIFIC (TYPE_MAIN_DECL (t))) retrofit_lang_decl (TYPE_MAIN_DECL (t)); DECL_SORTED_FIELDS (TYPE_MAIN_DECL (t)) = field_vec; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8f77d10..aad82c0 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1,5 +1,5 @@ /* Definitions for C++ parsing and type checking. - Copyright (C) 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + Copyright (C) 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2003, 2000, 2001, 2002 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) @@ -23,6 +23,7 @@ Boston, MA 02111-1307, USA. */ #ifndef GCC_CP_TREE_H #define GCC_CP_TREE_H +#include "ggc.h" #include "function.h" #include "hashtab.h" #include "splay-tree.h" @@ -1182,7 +1183,7 @@ struct lang_type_class GTY(()) tree as_base; tree pure_virtuals; tree friend_classes; - tree methods; + tree GTY ((reorder ("resort_type_method_vec"))) methods; tree key_method; tree decl_list; tree template_info; @@ -1782,7 +1783,7 @@ struct lang_decl_flags GTY(()) tree GTY ((tag ("0"))) access; /* For VAR_DECL in function, this is DECL_DISCRIMINATOR. */ - int discriminator; + int GTY ((tag ("1"))) discriminator; /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is THUNK_VIRTUAL_OFFSET. */ @@ -1790,6 +1791,9 @@ struct lang_decl_flags GTY(()) } GTY ((desc ("%1.u2sel"))) u2; }; +/* sorted_fields is sorted based on a pointer, so we need to be able + to resort it if pointers get rearranged. */ + struct lang_decl GTY(()) { struct lang_decl_flags decl_flags; @@ -1827,7 +1831,8 @@ struct lang_decl GTY(()) union lang_decl_u3 { - tree GTY ((tag ("0"))) sorted_fields; + tree GTY ((tag ("0"), reorder ("resort_sorted_fields"))) + sorted_fields; struct cp_token_cache * GTY ((tag ("2"))) pending_inline_info; struct language_function * GTY ((tag ("1"))) saved_language_function; @@ -3555,7 +3560,7 @@ extern void init_reswords PARAMS ((void)); opname_tab[(int) MINUS_EXPR] == "-". */ extern const char **opname_tab, **assignop_tab; -typedef struct operator_name_info_t +typedef struct operator_name_info_t GTY(()) { /* The IDENTIFIER_NODE for the operator. */ tree identifier; @@ -3568,9 +3573,11 @@ typedef struct operator_name_info_t } operator_name_info_t; /* A mapping from tree codes to operator name information. */ -extern operator_name_info_t operator_name_info[]; +extern GTY(()) operator_name_info_t operator_name_info + [(int) LAST_CPLUS_TREE_CODE]; /* Similar, but for assignment operators. */ -extern operator_name_info_t assignment_operator_name_info[]; +extern GTY(()) operator_name_info_t assignment_operator_name_info + [(int) LAST_CPLUS_TREE_CODE]; /* in call.c */ extern bool check_dtor_name (tree, tree); @@ -3611,10 +3618,14 @@ extern tree in_charge_arg_for_name (tree); /* in class.c */ extern tree build_base_path PARAMS ((enum tree_code, tree, tree, int)); -extern tree convert_to_base (tree, tree, bool); +extern tree convert_to_base PARAMS ((tree, tree, bool)); extern tree build_vtbl_ref PARAMS ((tree, tree)); extern tree build_vfn_ref PARAMS ((tree, tree)); extern tree get_vtable_decl PARAMS ((tree, int)); +extern void resort_sorted_fields + PARAMS ((void *, void *, gt_pointer_operator, void *)); +extern void resort_type_method_vec + PARAMS ((void *, void *, gt_pointer_operator, void *)); extern void add_method PARAMS ((tree, tree, int)); extern int currently_open_class PARAMS ((tree)); extern tree currently_open_derived_class PARAMS ((tree)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 35a14e8..29a7a7f 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -44,7 +44,6 @@ Boston, MA 02111-1307, USA. */ #include "except.h" #include "toplev.h" #include "hashtab.h" -#include "ggc.h" #include "tm_p.h" #include "target.h" #include "c-common.h" @@ -2731,7 +2730,7 @@ pushtag (tree name, tree type, int globalize) /* Counter used to create anonymous type names. */ -static int anon_cnt = 0; +static GTY(()) int anon_cnt; /* Return an IDENTIFIER which can be used as a name for anonymous structs and unions. */ diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 6363007..2491c8a 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -42,7 +42,6 @@ Boston, MA 02111-1307, USA. */ #include "output.h" #include "except.h" #include "toplev.h" -#include "ggc.h" #include "timevar.h" #include "cpplib.h" #include "target.h" @@ -2589,6 +2588,9 @@ finish_file () if (! global_bindings_p () || current_class_type || decl_namespace_list) return; + if (pch_file) + c_common_write_pch (); + /* Otherwise, GDB can get confused, because in only knows about source for LINENO-1 lines. */ lineno -= 1; diff --git a/gcc/cp/g++spec.c b/gcc/cp/g++spec.c index 8c1e3ae..75a1d7c 100644 --- a/gcc/cp/g++spec.c +++ b/gcc/cp/g++spec.c @@ -60,14 +60,16 @@ lang_specific_driver (in_argc, in_argv, in_added_libraries) /* If nonzero, the user gave us the `-v' flag. */ int saw_verbose_flag = 0; - /* This will be 0 if we encounter a situation where we should not - link in libstdc++. */ - int library = 1; + /* This is a tristate: + -1 means we should not link in libstdc++ + 0 means we should link in libstdc++ if it is needed + 1 means libstdc++ is needed and should be linked in. */ + int library = 0; /* The number of arguments being added to what's in argv, other than libraries. We use this to track the number of times we've inserted -xc++/-xnone. */ - int added = 2; + int added = 0; /* Used to track options that take arguments, so we don't go wrapping those with -xc++/-xnone. */ @@ -131,10 +133,10 @@ lang_specific_driver (in_argc, in_argv, in_added_libraries) if (argv[i][0] == '-') { - if (library != 0 && (strcmp (argv[i], "-nostdlib") == 0 - || strcmp (argv[i], "-nodefaultlibs") == 0)) + if (strcmp (argv[i], "-nostdlib") == 0 + || strcmp (argv[i], "-nodefaultlibs") == 0) { - library = 0; + library = -1; } else if (strcmp (argv[i], "-lm") == 0 || strcmp (argv[i], "-lmath") == 0 @@ -152,31 +154,37 @@ lang_specific_driver (in_argc, in_argv, in_added_libraries) else if (strcmp (argv[i], "-pg") == 0 || strcmp (argv[i], "-p") == 0) saw_profile_flag++; else if (strcmp (argv[i], "-v") == 0) + saw_verbose_flag = 1; + else if (strncmp (argv[i], "-x", 2) == 0) { - saw_verbose_flag = 1; - if (argc == 2) + if (library == 0) { - /* If they only gave us `-v', don't try to link - in libg++. */ - library = 0; + const char * arg; + if (argv[i][2] != '\0') + arg = argv[i]+2; + else if (argv[i+1] != NULL) + arg = argv[i+1]; + else /* Error condition, message will be printed later. */ + arg = ""; + if (strcmp (arg, "c++") == 0 + || strcmp (arg, "c++-cpp-output") == 0) + library = 1; } + saw_speclang = 1; } - else if (strncmp (argv[i], "-x", 2) == 0) - saw_speclang = 1; else if (((argv[i][2] == '\0' && (char *)strchr ("bBVDUoeTuIYmLiA", argv[i][1]) != NULL) || strcmp (argv[i], "-Xlinker") == 0 || strcmp (argv[i], "-Tdata") == 0)) quote = argv[i]; - else if (library != 0 && ((argv[i][2] == '\0' - && (char *) strchr ("cSEM", argv[i][1]) != NULL) - || strcmp (argv[i], "-MM") == 0 - || strcmp (argv[i], "-fsyntax-only") == 0)) + else if ((argv[i][2] == '\0' + && (char *) strchr ("cSEM", argv[i][1]) != NULL) + || strcmp (argv[i], "-MM") == 0 + || strcmp (argv[i], "-fsyntax-only") == 0) { /* Don't specify libraries if we won't link, since that would cause a warning. */ - library = 0; - added -= 2; + library = -1; } else if (strcmp (argv[i], "-static-libgcc") == 0 || strcmp (argv[i], "-static") == 0) @@ -195,16 +203,28 @@ lang_specific_driver (in_argc, in_argv, in_added_libraries) continue; } - /* If the filename ends in .c or .i, put options around it. + /* If the filename ends in .[chi], put options around it. But not if a specified -x option is currently active. */ len = strlen (argv[i]); if (len > 2 - && (argv[i][len - 1] == 'c' || argv[i][len - 1] == 'i') + && (argv[i][len - 1] == 'c' + || argv[i][len - 1] == 'i' + || argv[i][len - 1] == 'h') && argv[i][len - 2] == '.') { args[i] |= LANGSPEC; added += 2; } + + /* If we don't know that this is a header file, we might + need to be linking in the libraries. */ + if (library == 0) + { + if ((len <= 2 || strcmp (argv[i] + (len - 2), ".H") != 0) + && (len <= 2 || strcmp (argv[i] + (len - 2), ".h") != 0) + && (len <= 3 || strcmp (argv[i] + (len - 3), ".hh") != 0)) + library = 1; + } } } @@ -212,7 +232,7 @@ lang_specific_driver (in_argc, in_argv, in_added_libraries) fatal ("argument to `%s' missing\n", quote); /* If we know we don't have to do anything, bail now. */ - if (! added && ! library) + if (! added && library <= 0) { free (args); return; @@ -225,7 +245,7 @@ lang_specific_driver (in_argc, in_argv, in_added_libraries) #endif /* Make sure to have room for the trailing NULL argument. */ - num_args = argc + added + need_math + shared_libgcc + 1; + num_args = argc + added + need_math + shared_libgcc + (library > 0) + 1; arglist = (const char **) xmalloc (num_args * sizeof (char *)); i = 0; @@ -241,27 +261,37 @@ lang_specific_driver (in_argc, in_argv, in_added_libraries) /* Make sure -lstdc++ is before the math library, since libstdc++ itself uses those math routines. */ - if (!saw_math && (args[i] & MATHLIB) && library) + if (!saw_math && (args[i] & MATHLIB) && library > 0) { --j; saw_math = argv[i]; } - if (!saw_libc && (args[i] & WITHLIBC) && library) + if (!saw_libc && (args[i] & WITHLIBC) && library > 0) { --j; saw_libc = argv[i]; } - /* Wrap foo.c and foo.i files in a language specification to + /* Wrap foo.[chi] files in a language specification to force the gcc compiler driver to run cc1plus on them. */ if (args[i] & LANGSPEC) { int len = strlen (argv[i]); - if (argv[i][len - 1] == 'i') - arglist[j++] = "-xc++-cpp-output"; - else - arglist[j++] = "-xc++"; + switch (argv[i][len - 1]) + { + case 'c': + arglist[j++] = "-xc++"; + break; + case 'i': + arglist[j++] = "-xc++-cpp-output"; + break; + case 'h': + arglist[j++] = "-xc++-header"; + break; + default: + abort (); + } arglist[j++] = argv[i]; arglist[j] = "-xnone"; } @@ -271,7 +301,7 @@ lang_specific_driver (in_argc, in_argv, in_added_libraries) } /* Add `-lstdc++' if we haven't already done so. */ - if (library) + if (library > 0) { arglist[j++] = saw_profile_flag ? LIBSTDCXX_PROFILE : LIBSTDCXX; added_libraries++; @@ -285,7 +315,7 @@ lang_specific_driver (in_argc, in_argv, in_added_libraries) } if (saw_math) arglist[j++] = saw_math; - else if (library && need_math) + else if (library > 0 && need_math) { arglist[j++] = saw_profile_flag ? MATH_LIBRARY_PROFILE : MATH_LIBRARY; added_libraries++; diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 2fd0c50..964ee1e 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -34,7 +34,6 @@ Boston, MA 02111-1307, USA. */ #include "output.h" #include "except.h" #include "toplev.h" -#include "ggc.h" static void construct_virtual_base (tree, tree); static void expand_aggr_init_1 PARAMS ((tree, tree, tree, tree, int)); diff --git a/gcc/cp/lang-specs.h b/gcc/cp/lang-specs.h index e826467..cf4ca4c 100644 --- a/gcc/cp/lang-specs.h +++ b/gcc/cp/lang-specs.h @@ -33,6 +33,19 @@ Boston, MA 02111-1307, USA. */ {".c++", "@c++", 0}, {".C", "@c++", 0}, {".CPP", "@c++", 0}, + {".H", "@c++-header", 0}, + {".hh", "@c++-header", 0}, + {"@c++-header", + "%{E|M|MM:cc1plus -E %{!no-gcc:-D__GNUG__=%v1}\ + %(cpp_options) %2 %(cpp_debug_options)}\ + %{!E:%{!M:%{!MM:\ + %{save-temps:cc1plus -E %{!no-gcc:-D__GNUG__=%v1}\ + %(cpp_options) %2 %b.ii \n}\ + cc1plus %{save-temps:-fpreprocessed %b.ii}\ + %{!save-temps:%(cpp_unique_options) %{!no-gcc:-D__GNUG__=%v1}}\ + %(cc1_options) %2 %{+e1*}\ + -o %g.s %{!o*:--output-pch=%i.pch} %W{o*:--output-pch=%*}%V}}}", + CPLUSPLUS_CPP_SPEC}, {"@c++", "%{E|M|MM:cc1plus -E %{!no-gcc:-D__GNUG__=%v1}\ %(cpp_options) %2 %(cpp_debug_options)}\ diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index 2975399..5749fc4 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -36,7 +36,6 @@ Boston, MA 02111-1307, USA. */ #include "c-pragma.h" #include "toplev.h" #include "output.h" -#include "ggc.h" #include "tm_p.h" #include "timevar.h" #include "diagnostic.h" @@ -380,10 +379,7 @@ init_reswords () int mask = ((flag_no_asm ? D_ASM : 0) | (flag_no_gnu_keywords ? D_EXT : 0)); - /* It is not necessary to register ridpointers as a GC root, because - all the trees it points to are permanently interned in the - get_identifier hash anyway. */ - ridpointers = (tree *) xcalloc ((int) RID_MAX, sizeof (tree)); + ridpointers = (tree *) ggc_calloc ((int) RID_MAX, sizeof (tree)); for (i = 0; i < ARRAY_SIZE (reswords); i++) { id = get_identifier (reswords[i].word); diff --git a/gcc/cp/method.c b/gcc/cp/method.c index f4960b2..883a81f 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1,7 +1,7 @@ /* Handle the hair of processing (but not expanding) inline functions. Also manage function and variable name overloading. - Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000 Free Software Foundation, Inc. + Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -34,7 +34,6 @@ Boston, MA 02111-1307, USA. */ #include "output.h" #include "flags.h" #include "toplev.h" -#include "ggc.h" #include "tm_p.h" #include "target.h" diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index fe924f4..8f08c9a 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -31,7 +31,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "integrate.h" #include "toplev.h" #include "varray.h" -#include "ggc.h" #include "params.h" #include "hashtab.h" #include "debug.h" diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e88045d..629ba5d 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -32,7 +32,6 @@ #include "decl.h" #include "flags.h" #include "diagnostic.h" -#include "ggc.h" #include "toplev.h" #include "output.h" @@ -213,8 +212,8 @@ typedef struct cp_lexer GTY (()) /* Prototypes. */ -static cp_lexer *cp_lexer_new - PARAMS ((bool)); +static cp_lexer *cp_lexer_new_main + PARAMS ((void)); static cp_lexer *cp_lexer_new_from_tokens PARAMS ((struct cp_token_cache *)); static int cp_lexer_saving_tokens @@ -292,29 +291,37 @@ static void cp_lexer_stop_debugging /* The stream to which debugging output should be written. */ static FILE *cp_lexer_debug_stream; -/* Create a new C++ lexer. If MAIN_LEXER_P is true the new lexer is - the main lexer -- i.e, the lexer that gets tokens from the - preprocessor. Otherwise, it is a lexer that uses a cache of stored - tokens. */ +/* Create a new main C++ lexer, the lexer that gets tokens from the + preprocessor. */ static cp_lexer * -cp_lexer_new (bool main_lexer_p) +cp_lexer_new_main (void) { cp_lexer *lexer; + cp_token first_token; + + /* It's possible that lexing the first token will load a PCH file, + which is a GC collection point. So we have to grab the first + token before allocating any memory. */ + cp_lexer_get_preprocessor_token (NULL, &first_token); + cpp_get_callbacks (parse_in)->valid_pch = NULL; /* Allocate the memory. */ lexer = (cp_lexer *) ggc_alloc_cleared (sizeof (cp_lexer)); /* Create the circular buffer. */ lexer->buffer = ((cp_token *) - ggc_alloc (CP_TOKEN_BUFFER_SIZE * sizeof (cp_token))); + ggc_calloc (CP_TOKEN_BUFFER_SIZE, sizeof (cp_token))); lexer->buffer_end = lexer->buffer + CP_TOKEN_BUFFER_SIZE; - /* There are no tokens in the buffer. */ - lexer->last_token = lexer->buffer; + /* There is one token in the buffer. */ + lexer->last_token = lexer->buffer + 1; + lexer->first_token = lexer->buffer; + lexer->next_token = lexer->buffer; + memcpy (lexer->buffer, &first_token, sizeof (cp_token)); /* This lexer obtains more tokens by calling c_lex. */ - lexer->main_lexer_p = main_lexer_p; + lexer->main_lexer_p = true; /* Create the SAVED_TOKENS stack. */ VARRAY_INT_INIT (lexer->saved_tokens, CP_SAVED_TOKENS_SIZE, "saved_tokens"); @@ -339,15 +346,14 @@ cp_lexer_new_from_tokens (cp_token_cache *tokens) cp_token_block *block; ptrdiff_t num_tokens; - /* Create the lexer. */ - lexer = cp_lexer_new (/*main_lexer_p=*/false); + /* Allocate the memory. */ + lexer = (cp_lexer *) ggc_alloc_cleared (sizeof (cp_lexer)); /* Create a new buffer, appropriately sized. */ num_tokens = 0; for (block = tokens->first; block != NULL; block = block->next) num_tokens += block->num_tokens; - lexer->buffer = ((cp_token *) - ggc_alloc (num_tokens * sizeof (cp_token))); + lexer->buffer = ((cp_token *) ggc_alloc (num_tokens * sizeof (cp_token))); lexer->buffer_end = lexer->buffer + num_tokens; /* Install the tokens. */ @@ -365,6 +371,18 @@ cp_lexer_new_from_tokens (cp_token_cache *tokens) /* The buffer is full. */ lexer->last_token = lexer->first_token; + /* This lexer doesn't obtain more tokens. */ + lexer->main_lexer_p = false; + + /* Create the SAVED_TOKENS stack. */ + VARRAY_INT_INIT (lexer->saved_tokens, CP_SAVED_TOKENS_SIZE, "saved_tokens"); + + /* Create the STRINGS array. */ + VARRAY_TREE_INIT (lexer->string_tokens, 32, "strings"); + + /* Assume we are not debugging. */ + lexer->debugging_p = false; + return lexer; } @@ -610,7 +628,7 @@ cp_lexer_get_preprocessor_token (lexer, token) bool done; /* If this not the main lexer, return a terminating CPP_EOF token. */ - if (!lexer->main_lexer_p) + if (lexer != NULL && !lexer->main_lexer_p) { token->type = CPP_EOF; token->line_number = 0; @@ -2472,9 +2490,14 @@ static cp_parser * cp_parser_new () { cp_parser *parser; + cp_lexer *lexer; + + /* cp_lexer_new_main is called before calling ggc_alloc because + cp_lexer_new_main might load a PCH file. */ + lexer = cp_lexer_new_main (); parser = (cp_parser *) ggc_alloc_cleared (sizeof (cp_parser)); - parser->lexer = cp_lexer_new (/*main_lexer_p=*/true); + parser->lexer = lexer; parser->context = cp_parser_context_new (NULL); /* For now, we always accept GNU extensions. */ @@ -14422,9 +14445,7 @@ cp_parser_late_parsing_for_member (parser, member_function) /* Set the current source position to be the location of the first token in the saved inline body. */ - cp_lexer_set_source_position_from_token - (parser->lexer, - cp_lexer_peek_token (parser->lexer)); + (void) cp_lexer_peek_token (parser->lexer); /* Let the front end know that we going to be defining this function. */ @@ -14477,8 +14498,7 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn) /* Set the current source position to be the location of the first token in the default argument. */ - cp_lexer_set_source_position_from_token - (parser->lexer, cp_lexer_peek_token (parser->lexer)); + (void) cp_lexer_peek_token (parser->lexer); /* Local variable names (and the `this' keyword) may not appear in a default argument. */ @@ -14996,6 +15016,8 @@ yyparse () the_parser = cp_parser_new (); error_occurred = cp_parser_translation_unit (the_parser); the_parser = NULL; + + finish_file (); return error_occurred; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 7802e25..e7486af 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -41,7 +41,6 @@ Boston, MA 02111-1307, USA. */ #include "except.h" #include "toplev.h" #include "rtl.h" -#include "ggc.h" #include "timevar.h" /* The type of functions taking a tree, and some additional data, and diff --git a/gcc/cp/repo.c b/gcc/cp/repo.c index 105e4df..603b04e 100644 --- a/gcc/cp/repo.c +++ b/gcc/cp/repo.c @@ -35,7 +35,6 @@ Boston, MA 02111-1307, USA. */ #include "input.h" #include "obstack.h" #include "toplev.h" -#include "ggc.h" #include "diagnostic.h" static tree repo_get_id (tree); diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 13ed4b0..5e9b395 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -33,7 +33,6 @@ Boston, MA 02111-1307, USA. */ #include "flags.h" #include "rtl.h" #include "output.h" -#include "ggc.h" #include "toplev.h" #include "stack.h" diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 0aeaa0d..3ed9f2e 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3,7 +3,7 @@ building RTL. These routines are used both during actual parsing and during the instantiation of template functions. - Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Written by Mark Mitchell (mmitchell@usa.net) based on code found formerly in parse.y and pt.c. @@ -35,7 +35,6 @@ #include "lex.h" #include "toplev.h" #include "flags.h" -#include "ggc.h" #include "rtl.h" #include "expr.h" #include "output.h" @@ -1628,8 +1627,6 @@ finish_translation_unit () /* Do file scope __FUNCTION__ et al. */ finish_fname_decls (); - - finish_file (); } /* Finish a template type parameter, specified as AGGR IDENTIFIER. diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 93c62da..a3b6ff1 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -30,7 +30,6 @@ Boston, MA 02111-1307, USA. */ #include "real.h" #include "rtl.h" #include "toplev.h" -#include "ggc.h" #include "insn-config.h" #include "integrate.h" #include "tree-inline.h" diff --git a/gcc/cppfiles.c b/gcc/cppfiles.c index 4d82196..203619f 100644 --- a/gcc/cppfiles.c +++ b/gcc/cppfiles.c @@ -22,6 +22,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include "system.h" +#include #include "coretypes.h" #include "tm.h" #include "cpplib.h" @@ -87,6 +88,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This structure is used for the table of all includes. */ struct include_file { const char *name; /* actual path name of file */ + const char *header_name; /* the original header found */ const cpp_hashnode *cmacro; /* macro, if any, preventing reinclusion. */ const struct search_path *foundhere; /* location in search path where file was @@ -98,6 +100,13 @@ struct include_file { unsigned short include_count; /* number of times file has been read */ unsigned short refcnt; /* number of stacked buffers using this file */ unsigned char mapped; /* file buffer is mmapped */ + unsigned char pch; /* 0: file not known to be a PCH. + 1: file is a PCH + (on return from find_include_file). + 2: file is not and never will be a valid + precompiled header. + 3: file is always a valid precompiled + header. */ }; /* Variable length record files on VMS will have a stat size that includes @@ -118,6 +127,7 @@ struct include_file { ((inc)->cmacro && ((inc)->cmacro == NEVER_REREAD \ || (inc)->cmacro->type == NT_MACRO)) #define NO_INCLUDE_PATH ((struct include_file *) -1) +#define INCLUDE_PCH_P(F) (((F)->pch & 1) != 0) static struct file_name_map *read_name_map PARAMS ((cpp_reader *, const char *)); @@ -130,6 +140,11 @@ static struct include_file * find_include_file PARAMS ((cpp_reader *, const cpp_token *, enum include_type)); static struct include_file *open_file PARAMS ((cpp_reader *, const char *)); +static struct include_file *validate_pch PARAMS ((cpp_reader *, + const char *, + const char *)); +static struct include_file *open_file_pch PARAMS ((cpp_reader *, + const char *)); static int read_include_file PARAMS ((cpp_reader *, struct include_file *)); static bool stack_include_file PARAMS ((cpp_reader *, struct include_file *)); static void purge_cache PARAMS ((struct include_file *)); @@ -212,6 +227,7 @@ find_or_create_entry (pfile, fname) { file = xcnew (struct include_file); file->name = name; + file->header_name = name; file->err_no = errno; node = splay_tree_insert (pfile->all_include_files, (splay_tree_key) file->name, @@ -306,6 +322,89 @@ open_file (pfile, filename) return 0; } +static struct include_file * +validate_pch (pfile, filename, pchname) + cpp_reader *pfile; + const char *filename; + const char *pchname; +{ + struct include_file * file; + + file = open_file (pfile, pchname); + if (file == NULL) + return NULL; + if ((file->pch & 2) == 0) + file->pch = pfile->cb.valid_pch (pfile, pchname, file->fd); + if (INCLUDE_PCH_P (file)) + { + file->header_name = _cpp_simplify_pathname (xstrdup (filename)); + return file; + } + close (file->fd); + file->fd = -1; + return NULL; +} + + +/* Like open_file, but also look for a precompiled header if (a) one exists + and (b) it is valid. */ +static struct include_file * +open_file_pch (pfile, filename) + cpp_reader *pfile; + const char *filename; +{ + if (filename[0] != '\0' + && pfile->cb.valid_pch != NULL) + { + size_t namelen = strlen (filename); + char *pchname = alloca (namelen + 5); + struct include_file * file; + splay_tree_node nd; + + memcpy (pchname, filename, namelen); + memcpy (pchname + namelen, ".pch", 5); + + nd = find_or_create_entry (pfile, pchname); + file = (struct include_file *) nd->value; + + if (file != NULL) + { + if (stat (file->name, &file->st) == 0 && S_ISDIR (file->st.st_mode)) + { + DIR * thedir; + struct dirent *d; + size_t subname_len = namelen + 64; + char *subname = xmalloc (subname_len); + + thedir = opendir (pchname); + if (thedir == NULL) + return NULL; + memcpy (subname, pchname, namelen + 4); + subname[namelen+4] = '/'; + while ((d = readdir (thedir)) != NULL) + { + if (strlen (d->d_name) + namelen + 7 > subname_len) + { + subname_len = strlen (d->d_name) + namelen + 64; + subname = xrealloc (subname, subname_len); + } + strcpy (subname + namelen + 5, d->d_name); + file = validate_pch (pfile, filename, subname); + if (file) + break; + } + closedir (thedir); + free (subname); + } + else + file = validate_pch (pfile, filename, pchname); + if (file) + return file; + } + } + return open_file (pfile, filename); +} + /* Place the file referenced by INC into a new buffer on the buffer stack, unless there are errors, or the file is not re-included because of e.g. multiple-include guards. Returns true if a buffer @@ -332,6 +431,15 @@ stack_include_file (pfile, inc) deps_add_dep (pfile->deps, inc->name); } + /* PCH files get dealt with immediately. */ + if (INCLUDE_PCH_P (inc)) + { + pfile->cb.read_pch (pfile, inc->name, inc->fd, inc->header_name); + close (inc->fd); + inc->fd = -1; + return false; + } + /* Not in cache? */ if (! inc->buffer) { @@ -579,7 +687,7 @@ find_include_file (pfile, header, type) char *name, *n; if (IS_ABSOLUTE_PATHNAME (fname)) - return open_file (pfile, fname); + return open_file_pch (pfile, fname); /* For #include_next, skip in the search path past the dir in which the current file was found, but if it was found via an absolute @@ -615,7 +723,7 @@ find_include_file (pfile, header, type) else n = name; - file = open_file (pfile, n); + file = open_file_pch (pfile, n); if (file) { file->foundhere = path; @@ -757,6 +865,9 @@ _cpp_read_file (pfile, fname) cpp_reader *pfile; const char *fname; { + /* This uses open_file, because we don't allow a PCH to be used as + the toplevel compilation (that would prevent re-compiling an + existing PCH without deleting it first). */ struct include_file *f = open_file (pfile, fname); if (f == NULL) diff --git a/gcc/cpphash.h b/gcc/cpphash.h index 16e8dfe..d5a0b5d 100644 --- a/gcc/cpphash.h +++ b/gcc/cpphash.h @@ -449,6 +449,10 @@ struct cpp_reader /* Used to save the original line number during traditional preprocessing. */ unsigned int saved_line; + + /* A saved list of the defined macros, for dependency checking + of precompiled headers. */ + struct cpp_savedstate *savedstate; }; /* Character classes. Based on the more primitive macros in safe-ctype.h. @@ -542,6 +546,8 @@ extern void _cpp_maybe_push_include_file PARAMS ((cpp_reader *)); extern int _cpp_test_assertion PARAMS ((cpp_reader *, unsigned int *)); extern int _cpp_handle_directive PARAMS ((cpp_reader *, int)); extern void _cpp_define_builtin PARAMS ((cpp_reader *, const char *)); +extern char ** _cpp_save_pragma_names PARAMS ((cpp_reader *)); +extern void _cpp_restore_pragma_names PARAMS ((cpp_reader *, char **)); extern void _cpp_do__Pragma PARAMS ((cpp_reader *)); extern void _cpp_init_directives PARAMS ((cpp_reader *)); extern void _cpp_init_internal_pragmas PARAMS ((cpp_reader *)); diff --git a/gcc/cpplib.c b/gcc/cpplib.c index e032e75..1019a2a 100644 --- a/gcc/cpplib.c +++ b/gcc/cpplib.c @@ -121,6 +121,11 @@ static struct pragma_entry *lookup_pragma_entry static struct pragma_entry *insert_pragma_entry PARAMS ((cpp_reader *, struct pragma_entry **, const cpp_hashnode *, pragma_cb)); +static int count_registered_pragmas PARAMS ((struct pragma_entry *)); +static char ** save_registered_pragmas + PARAMS ((struct pragma_entry *, char **)); +static char ** restore_registered_pragmas + PARAMS ((cpp_reader *, struct pragma_entry *, char **)); static void do_pragma_once PARAMS ((cpp_reader *)); static void do_pragma_poison PARAMS ((cpp_reader *)); static void do_pragma_system_header PARAMS ((cpp_reader *)); @@ -1085,6 +1090,85 @@ _cpp_init_internal_pragmas (pfile) cpp_register_pragma (pfile, "GCC", "dependency", do_pragma_dependency); } +/* Return the number of registered pragmas in PE. */ + +static int +count_registered_pragmas (pe) + struct pragma_entry *pe; +{ + int ct = 0; + for (; pe != NULL; pe = pe->next) + { + if (pe->is_nspace) + ct += count_registered_pragmas (pe->u.space); + ct++; + } + return ct; +} + +/* Save into SD the names of the registered pragmas referenced by PE, + and return a pointer to the next free space in SD. */ + +static char ** +save_registered_pragmas (pe, sd) + struct pragma_entry *pe; + char **sd; +{ + for (; pe != NULL; pe = pe->next) + { + if (pe->is_nspace) + sd = save_registered_pragmas (pe->u.space, sd); + *sd++ = xmemdup (HT_STR (&pe->pragma->ident), + HT_LEN (&pe->pragma->ident), + HT_LEN (&pe->pragma->ident) + 1); + } + return sd; +} + +/* Return a newly-allocated array which saves the names of the + registered pragmas. */ + +char ** +_cpp_save_pragma_names (pfile) + cpp_reader *pfile; +{ + int ct = count_registered_pragmas (pfile->pragmas); + char **result = xnewvec (char *, ct); + (void) save_registered_pragmas (pfile->pragmas, result); + return result; +} + +/* Restore from SD the names of the registered pragmas referenced by PE, + and return a pointer to the next unused name in SD. */ + +static char ** +restore_registered_pragmas (pfile, pe, sd) + cpp_reader *pfile; + struct pragma_entry *pe; + char **sd; +{ + for (; pe != NULL; pe = pe->next) + { + if (pe->is_nspace) + sd = restore_registered_pragmas (pfile, pe->u.space, sd); + pe->pragma = cpp_lookup (pfile, U *sd, strlen (*sd)); + free (*sd); + sd++; + } + return sd; +} + +/* Restore the names of the registered pragmas from SAVED. */ + +void +_cpp_restore_pragma_names (pfile, saved) + cpp_reader *pfile; + char **saved; +{ + (void) restore_registered_pragmas (pfile, pfile->pragmas, saved); + free (saved); +} + /* Pragmata handling. We handle some, and pass the rest on to the front end. C99 defines three pragmas and says that no macro expansion is to be performed on them; whether or not macro diff --git a/gcc/cpplib.h b/gcc/cpplib.h index 271a755..bccfecf 100644 --- a/gcc/cpplib.h +++ b/gcc/cpplib.h @@ -400,6 +400,12 @@ struct cpp_options /* Nonzero means __STDC__ should have the value 0 in system headers. */ unsigned char stdc_0_in_system_headers; + + /* True to warn about precompiled header files we couldn't use. */ + bool warn_invalid_pch; + + /* True if dependencies should be restored from a precompiled header. */ + bool restore_pch_deps; }; /* Call backs. */ @@ -417,6 +423,8 @@ struct cpp_callbacks /* Called when the client has a chance to properly register built-ins with cpp_define() and cpp_assert(). */ void (*register_builtins) PARAMS ((cpp_reader *)); + int (*valid_pch) PARAMS ((cpp_reader *, const char *, int)); + void (*read_pch) PARAMS ((cpp_reader *, const char *, int, const char *)); }; /* Name under which this program was invoked. */ @@ -472,7 +480,7 @@ enum builtin_type /* The common part of an identifier node shared amongst all 3 C front ends. Also used to store CPP identifiers, which are a superset of identifiers in the grammatical sense. */ -struct cpp_hashnode +struct cpp_hashnode GTY(()) { struct ht_identifier ident; unsigned int is_directive : 1; @@ -485,11 +493,15 @@ struct cpp_hashnode union _cpp_hashnode_value { - cpp_macro *macro; /* If a macro. */ - struct answer *answers; /* Answers to an assertion. */ - enum builtin_type builtin; /* Code for a builtin macro. */ - unsigned short arg_index; /* Macro argument index. */ - } value; + /* If a macro. */ + cpp_macro * GTY((skip (""))) macro; + /* Answers to an assertion. */ + struct answer * GTY ((skip (""))) answers; + /* Code for a builtin macro. */ + enum builtin_type GTY ((tag ("1"))) builtin; + /* Macro argument index. */ + unsigned short GTY ((tag ("0"))) arg_index; + } GTY ((desc ("0"))) value; }; /* Call this first to get a handle to pass to other functions. */ @@ -722,6 +734,17 @@ extern unsigned char *cpp_quote_string PARAMS ((unsigned char *, extern int cpp_included PARAMS ((cpp_reader *, const char *)); extern void cpp_make_system_header PARAMS ((cpp_reader *, int, int)); +/* In cpppch.c */ +struct save_macro_data; +extern int cpp_save_state PARAMS ((cpp_reader *, FILE *)); +extern int cpp_write_pch_deps PARAMS ((cpp_reader *, FILE *)); +extern int cpp_write_pch_state PARAMS ((cpp_reader *, FILE *)); +extern int cpp_valid_state PARAMS ((cpp_reader *, const char *, int)); +extern void cpp_prepare_state PARAMS ((cpp_reader *, + struct save_macro_data **)); +extern int cpp_read_state PARAMS ((cpp_reader *, const char *, FILE *, + struct save_macro_data *)); + /* In cppmain.c */ extern void cpp_preprocess_file PARAMS ((cpp_reader *, const char *, FILE *)); diff --git a/gcc/cpppch.c b/gcc/cpppch.c new file mode 100644 index 0000000..e7f0c91 --- /dev/null +++ b/gcc/cpppch.c @@ -0,0 +1,684 @@ +/* Part of CPP library. (Precompiled header reading/writing.) + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "cpplib.h" +#include "cpphash.h" +#include "intl.h" +#include "hashtab.h" +#include "mkdeps.h" + +static int write_macdef PARAMS ((cpp_reader *, cpp_hashnode *, void *)); +static int save_idents PARAMS ((cpp_reader *, cpp_hashnode *, void *)); +static hashval_t hashmem PARAMS ((const void *, size_t)); +static hashval_t cpp_string_hash PARAMS ((const void *)); +static int cpp_string_eq PARAMS ((const void *, const void *)); +static int count_defs PARAMS ((cpp_reader *, cpp_hashnode *, void *)); +static int write_defs PARAMS ((cpp_reader *, cpp_hashnode *, void *)); +static int save_macros PARAMS ((cpp_reader *, cpp_hashnode *, void *)); +static int reset_ht PARAMS ((cpp_reader *, cpp_hashnode *, void *)); + +/* This structure represents a macro definition on disk. */ +struct macrodef_struct +{ + unsigned int definition_length; + unsigned short name_length; + unsigned short flags; +}; + +/* This is how we write out a macro definition. + Suitable for being called by cpp_forall_identifiers. */ + +static int +write_macdef (pfile, hn, file_p) + cpp_reader *pfile; + cpp_hashnode *hn; + void *file_p; +{ + FILE *f = (FILE *) file_p; + switch (hn->type) + { + case NT_VOID: + if (! (hn->flags & NODE_POISONED)) + return 1; + + case NT_MACRO: + if ((hn->flags & NODE_BUILTIN)) + return 1; + + { + struct macrodef_struct s; + const unsigned char *defn; + + s.name_length = NODE_LEN (hn); + s.flags = hn->flags & NODE_POISONED; + + if (hn->type == NT_MACRO) + { + defn = cpp_macro_definition (pfile, hn); + s.definition_length = ustrlen (defn); + } + else + { + defn = NODE_NAME (hn); + s.definition_length = s.name_length; + } + + if (fwrite (&s, sizeof (s), 1, f) != 1 + || fwrite (defn, 1, s.definition_length, f) != s.definition_length) + { + cpp_errno (pfile, DL_ERROR, "while writing precompiled header"); + return 0; + } + } + return 1; + + case NT_ASSERTION: + /* Not currently implemented. */ + return 1; + + default: + abort (); + } +} + +/* This structure records the names of the defined macros. + It's also used as a callback structure for size_initial_idents + and save_idents. */ + +struct cpp_savedstate +{ + /* A hash table of the defined identifiers. */ + htab_t definedhash; + /* The size of the definitions of those identifiers (the size of + 'definedstrs'). */ + size_t hashsize; + /* Space for the next definition. Definitions are null-terminated + strings. */ + unsigned char *definedstrs; +}; + +/* Save this identifier into the state: put it in the hash table, + put the definition in 'definedstrs'. */ + +static int +save_idents (pfile, hn, ss_p) + cpp_reader *pfile ATTRIBUTE_UNUSED; + cpp_hashnode *hn; + void *ss_p; +{ + struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p; + + if (hn->type != NT_VOID) + { + struct cpp_string news; + void **slot; + + news.len = NODE_LEN (hn); + news.text= NODE_NAME (hn); + slot = htab_find_slot (ss->definedhash, &news, INSERT); + if (*slot == NULL) + { + struct cpp_string *sp; + unsigned char *text; + + sp = xmalloc (sizeof (struct cpp_string)); + *slot = sp; + + sp->len = NODE_LEN (hn); + sp->text = text = xmalloc (NODE_LEN (hn)); + memcpy (text, NODE_NAME (hn), NODE_LEN (hn)); + } + } + + return 1; +} + +/* Hash some memory in a generic way. */ + +static hashval_t +hashmem (p_p, sz) + const void *p_p; + size_t sz; +{ + const unsigned char *p = (const unsigned char *)p_p; + size_t i; + hashval_t h; + + h = 0; + for (i = 0; i < sz; i++) + h = h * 67 - (*p++ - 113); + return h; +} + +/* Hash a cpp string for the hashtable machinery. */ + +static hashval_t +cpp_string_hash (a_p) + const void *a_p; +{ + const struct cpp_string *a = (const struct cpp_string *) a_p; + return hashmem (a->text, a->len); +} + +/* Compare two cpp strings for the hashtable machinery. */ + +static int +cpp_string_eq (a_p, b_p) + const void *a_p; + const void *b_p; +{ + const struct cpp_string *a = (const struct cpp_string *) a_p; + const struct cpp_string *b = (const struct cpp_string *) b_p; + return (a->len == b->len + && memcmp (a->text, b->text, a->len) == 0); +} + +/* Save the current definitions of the cpp_reader for dependency + checking purposes. When writing a precompiled header, this should + be called at the same point in the compilation as cpp_valid_state + would be called when reading the precompiled header back in. */ + +int +cpp_save_state (r, f) + cpp_reader *r; + FILE *f; +{ + /* Save the list of non-void identifiers for the dependency checking. */ + r->savedstate = xmalloc (sizeof (struct cpp_savedstate)); + r->savedstate->definedhash = htab_create (100, cpp_string_hash, + cpp_string_eq, NULL); + cpp_forall_identifiers (r, save_idents, r->savedstate); + + /* Write out the list of defined identifiers. */ + cpp_forall_identifiers (r, write_macdef, f); + + return 0; +} + +/* Calculate the 'hashsize' field of the saved state. */ + +static int +count_defs (pfile, hn, ss_p) + cpp_reader *pfile ATTRIBUTE_UNUSED; + cpp_hashnode *hn; + void *ss_p; +{ + struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p; + + switch (hn->type) + { + case NT_MACRO: + if (hn->flags & NODE_BUILTIN) + return 1; + + /* else fall through. */ + + case NT_VOID: + { + struct cpp_string news; + void **slot; + + news.len = NODE_LEN (hn); + news.text = NODE_NAME (hn); + slot = htab_find (ss->definedhash, &news); + if (slot == NULL) + ss->hashsize += NODE_LEN (hn) + 1; + } + return 1; + + case NT_ASSERTION: + /* Not currently implemented. */ + return 1; + + default: + abort (); + } +} + +/* Write the identifiers into 'definedstrs' of the state. */ + +static int +write_defs (pfile, hn, ss_p) + cpp_reader *pfile ATTRIBUTE_UNUSED; + cpp_hashnode *hn; + void *ss_p; +{ + struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p; + + switch (hn->type) + { + case NT_MACRO: + if (hn->flags & NODE_BUILTIN) + return 1; + + /* else fall through. */ + + case NT_VOID: + { + struct cpp_string news; + void **slot; + + news.len = NODE_LEN (hn); + news.text = NODE_NAME (hn); + slot = htab_find (ss->definedhash, &news); + if (slot == NULL) + { + memcpy (ss->definedstrs, NODE_NAME (hn), NODE_LEN (hn)); + ss->definedstrs[NODE_LEN (hn)] = 0; + ss->definedstrs += NODE_LEN (hn) + 1; + } + } + return 1; + + case NT_ASSERTION: + /* Not currently implemented. */ + return 1; + + default: + abort (); + } +} + +/* Write out the remainder of the dependency information. This should be + called after the PCH is ready to be saved. */ + +int +cpp_write_pch_deps (r, f) + cpp_reader *r; + FILE *f; +{ + struct macrodef_struct z; + struct cpp_savedstate *const ss = r->savedstate; + unsigned char *definedstrs; + + ss->hashsize = 0; + + /* Write out the list of identifiers which have been seen and + weren't defined to anything previously. */ + cpp_forall_identifiers (r, count_defs, ss); + definedstrs = ss->definedstrs = xmalloc (ss->hashsize); + cpp_forall_identifiers (r, write_defs, ss); + memset (&z, 0, sizeof (z)); + z.definition_length = ss->hashsize; + if (fwrite (&z, sizeof (z), 1, f) != 1 + || fwrite (definedstrs, ss->hashsize, 1, f) != 1) + { + cpp_errno (r, DL_ERROR, "while writing precompiled header"); + return -1; + } + free (definedstrs); + + /* Free the saved state. */ + free (ss); + r->savedstate = NULL; + return 0; +} + +/* Write out the definitions of the preprocessor, in a form suitable for + cpp_read_state. */ + +int +cpp_write_pch_state (r, f) + cpp_reader *r; + FILE *f; +{ + struct macrodef_struct z; + + /* Write out the list of defined identifiers. */ + cpp_forall_identifiers (r, write_macdef, f); + memset (&z, 0, sizeof (z)); + if (fwrite (&z, sizeof (z), 1, f) != 1) + { + cpp_errno (r, DL_ERROR, "while writing precompiled header"); + return -1; + } + + if (!r->deps) + r->deps = deps_init (); + + if (deps_save (r->deps, f) != 0) + { + cpp_errno (r, DL_ERROR, "while writing precompiled header"); + return -1; + } + + return 0; +} + +/* Return nonzero if FD is a precompiled header which is consistent + with the preprocessor's current definitions. It will be consistent + when: + + - anything that was defined just before the PCH was generated + is defined the same way now; and + - anything that was not defined then, but is defined now, was not + used by the PCH. + + NAME is used to print warnings if `warn_invalid_pch' is set in the + reader's flags. +*/ + +int +cpp_valid_state (r, name, fd) + cpp_reader *r; + const char *name; + int fd; +{ + struct macrodef_struct m; + size_t namebufsz = 256; + unsigned char *namebuf = xmalloc (namebufsz); + unsigned char *undeftab = NULL; + unsigned int i; + + /* Read in the list of identifiers that must be defined + Check that they are defined in the same way. */ + for (;;) + { + cpp_hashnode *h; + const unsigned char *newdefn; + + if (read (fd, &m, sizeof (m)) != sizeof (m)) + goto error; + + if (m.name_length == 0) + break; + + if (m.definition_length > namebufsz) + { + free (namebuf); + namebufsz = m.definition_length + 256; + namebuf = xmalloc (namebufsz); + } + + if ((size_t)read (fd, namebuf, m.definition_length) + != m.definition_length) + goto error; + + h = cpp_lookup (r, namebuf, m.name_length); + if (m.flags & NODE_POISONED + || h->type != NT_MACRO + || h->flags & NODE_POISONED) + { + if (CPP_OPTION (r, warn_invalid_pch)) + cpp_error (r, DL_WARNING, + "%s: not used because `%.*s' not defined", + name, m.name_length, namebuf); + goto fail; + } + + newdefn = cpp_macro_definition (r, h); + + if (m.definition_length != ustrlen (newdefn) + || memcmp (namebuf, newdefn, m.definition_length) != 0) + { + if (CPP_OPTION (r, warn_invalid_pch)) + cpp_error (r, DL_WARNING, + "%s: not used because `%.*s' defined as `%s' not `%.*s'", + name, m.name_length, namebuf, newdefn + m.name_length, + m.definition_length - m.name_length, + namebuf + m.name_length); + goto fail; + } + } + free (namebuf); + namebuf = NULL; + + /* Read in the list of identifiers that must not be defined. + Check that they really aren't. */ + undeftab = xmalloc (m.definition_length); + if ((size_t) read (fd, undeftab, m.definition_length) != m.definition_length) + goto error; + for (i = 0; i < m.definition_length; ) + { + int l = ustrlen (undeftab + i); + cpp_hashnode *h; + h = cpp_lookup (r, undeftab + i, l); + if (h->type != NT_VOID + || h->flags & NODE_POISONED) + { + if (CPP_OPTION (r, warn_invalid_pch)) + cpp_error (r, DL_WARNING, "%s: not used because `%s' is defined", + name, undeftab + i); + goto fail; + } + i += l + 1; + } + free (undeftab); + + /* We win! */ + return 0; + + error: + cpp_errno (r, DL_ERROR, "while reading precompiled header"); + return -1; + + fail: + if (namebuf != NULL) + free (namebuf); + if (undeftab != NULL) + free (undeftab); + return 1; +} + +/* Save all the existing macros and assertions. + This code assumes that there might be hundreds, but not thousands of + existing definitions. */ + +struct save_macro_item { + struct save_macro_item *next; + struct cpp_hashnode macs[64]; +}; + +struct save_macro_data +{ + struct save_macro_item *macros; + size_t count; + char **saved_pragmas; +}; + +/* Save the definition of a single macro, so that it will persist across + a PCH restore. */ + +static int +save_macros (r, h, data_p) + cpp_reader *r ATTRIBUTE_UNUSED; + cpp_hashnode *h; + void *data_p; +{ + struct save_macro_data *data = (struct save_macro_data *)data_p; + if (h->type != NT_VOID + && (h->flags & NODE_BUILTIN) == 0) + { + cpp_hashnode *save; + if (data->count == ARRAY_SIZE (data->macros->macs)) + { + struct save_macro_item *d = data->macros; + data->macros = xmalloc (sizeof (struct save_macro_item)); + data->macros->next = d; + data->count = 0; + } + save = data->macros->macs + data->count; + data->count++; + memcpy (save, h, sizeof (struct cpp_hashnode)); + HT_STR (&save->ident) = xmemdup (HT_STR (HT_NODE (save)), + HT_LEN (HT_NODE (save)), + HT_LEN (HT_NODE (save)) + 1); + } + return 1; +} + +/* Prepare to restore the state, by saving the currently-defined + macros in 'data'. */ + +void +cpp_prepare_state (r, data) + cpp_reader *r; + struct save_macro_data **data; +{ + struct save_macro_data *d = xmalloc (sizeof (struct save_macro_data)); + + d->macros = NULL; + d->count = ARRAY_SIZE (d->macros->macs); + cpp_forall_identifiers (r, save_macros, d); + d->saved_pragmas = _cpp_save_pragma_names (r); + *data = d; +} + +/* Erase all the existing macros and assertions. */ + +static int +reset_ht (r, h, unused) + cpp_reader *r ATTRIBUTE_UNUSED; + cpp_hashnode *h; + void *unused ATTRIBUTE_UNUSED; +{ + if (h->type != NT_VOID + && (h->flags & NODE_BUILTIN) == 0) + { + h->type = NT_VOID; + memset (&h->value, 0, sizeof (h->value)); + } + return 1; +} + +/* Given a precompiled header that was previously determined to be valid, + apply all its definitions (and undefinitions) to the current state. + DEPNAME is passed to deps_restore. */ + +int +cpp_read_state (r, name, f, data) + cpp_reader *r; + const char *name; + FILE *f; + struct save_macro_data *data; +{ + struct macrodef_struct m; + size_t defnlen = 256; + unsigned char *defn = xmalloc (defnlen); + struct lexer_state old_state; + struct save_macro_item *d; + size_t i, mac_count; + int saved_line = r->line; + + /* Erase all the existing hashtable entries for macros. At this + point, they're all from the PCH file, and their pointers won't be + valid. */ + cpp_forall_identifiers (r, reset_ht, NULL); + + /* Restore spec_nodes, which will be full of references to the old + hashtable entries and so will now be invalid. */ + { + struct spec_nodes *s = &r->spec_nodes; + s->n_defined = cpp_lookup (r, DSC("defined")); + s->n_true = cpp_lookup (r, DSC("true")); + s->n_false = cpp_lookup (r, DSC("false")); + s->n__VA_ARGS__ = cpp_lookup (r, DSC("__VA_ARGS__")); + } + + /* Run through the carefully-saved macros, insert them. */ + d = data->macros; + mac_count = data->count; + while (d) + { + struct save_macro_item *nextd; + for (i = 0; i < mac_count; i++) + { + cpp_hashnode *h; + + h = cpp_lookup (r, HT_STR (HT_NODE (&d->macs[i])), + HT_LEN (HT_NODE (&d->macs[i]))); + h->type = d->macs[i].type; + h->flags = d->macs[i].flags; + h->value = d->macs[i].value; + free ((void *)HT_STR (HT_NODE (&d->macs[i]))); + } + nextd = d->next; + free (d); + d = nextd; + mac_count = ARRAY_SIZE (d->macs); + } + + _cpp_restore_pragma_names (r, data->saved_pragmas); + + free (data); + + old_state = r->state; + + r->state.in_directive = 1; + r->state.prevent_expansion = 1; + r->state.angled_headers = 0; + + /* Read in the identifiers that must be defined. */ + for (;;) + { + cpp_hashnode *h; + + if (fread (&m, sizeof (m), 1, f) != 1) + goto error; + + if (m.name_length == 0) + break; + + if (defnlen < m.definition_length + 1) + { + defnlen = m.definition_length + 256; + defn = xrealloc (defn, defnlen); + } + + if (fread (defn, 1, m.definition_length, f) != m.definition_length) + goto error; + defn[m.definition_length] = '\0'; + + h = cpp_lookup (r, defn, m.name_length); + + if (h->type == NT_MACRO) + _cpp_free_definition (h); + if (m.flags & NODE_POISONED) + h->flags |= NODE_POISONED | NODE_DIAGNOSTIC; + else if (m.name_length != m.definition_length) + { + if (cpp_push_buffer (r, defn + m.name_length, + m.definition_length - m.name_length, + true, 1) != NULL) + { + if (!_cpp_create_definition (r, h)) + abort (); + _cpp_pop_buffer (r); + } + else + abort (); + } + } + + r->state = old_state; + r->line = saved_line; + free (defn); + defn = NULL; + + if (deps_restore (r->deps, f, CPP_OPTION (r, restore_pch_deps) ? name : NULL) + != 0) + goto error; + + return 0; + + error: + cpp_errno (r, DL_ERROR, "while reading precompiled header"); + return -1; +} diff --git a/gcc/dbxout.c b/gcc/dbxout.c index 5fcd28d..480ef82 100644 --- a/gcc/dbxout.c +++ b/gcc/dbxout.c @@ -137,57 +137,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #define STABS_GCC_MARKER "gcc2_compiled." #endif -/* Typical USG systems don't have stab.h, and they also have - no use for DBX-format debugging info. */ - -#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) - -/* Nonzero if we have actually used any of the GDB extensions - to the debugging format. The idea is that we use them for the - first time only if there's a strong reason, but once we have done that, - we use them whenever convenient. */ - -static int have_used_extensions = 0; - -/* Number for the next N_SOL filename stabs label. The number 0 is reserved - for the N_SO filename stabs label. */ - -#if defined (DBX_DEBUGGING_INFO) && !defined (DBX_OUTPUT_SOURCE_FILENAME) -static int source_label_number = 1; -#endif - -#ifdef DEBUG_SYMS_TEXT -#define FORCE_TEXT function_section (current_function_decl); -#else -#define FORCE_TEXT -#endif - -#include "gstab.h" - -#define STAB_CODE_TYPE enum __stab_debug_code - -/* 1 if PARM is passed to this function in memory. */ - -#define PARM_PASSED_IN_MEMORY(PARM) \ - (GET_CODE (DECL_INCOMING_RTL (PARM)) == MEM) - -/* A C expression for the integer offset value of an automatic variable - (N_LSYM) having address X (an RTX). */ -#ifndef DEBUGGER_AUTO_OFFSET -#define DEBUGGER_AUTO_OFFSET(X) \ - (GET_CODE (X) == PLUS ? INTVAL (XEXP (X, 1)) : 0) -#endif - -/* A C expression for the integer offset value of an argument (N_PSYM) - having address X (an RTX). The nominal offset is OFFSET. */ -#ifndef DEBUGGER_ARG_OFFSET -#define DEBUGGER_ARG_OFFSET(OFFSET, X) (OFFSET) -#endif - -/* Stream for writing to assembler file. */ - -static FILE *asmfile; - /* Last source file name mentioned in a NOTE insn. */ static const char *lastfile; @@ -205,13 +154,11 @@ enum typestatus {TYPE_UNSEEN, TYPE_XREF, TYPE_DEFINED}; The file_number and type_number elements are used if DBX_USE_BINCL is defined. */ -struct typeinfo +struct typeinfo GTY(()) { enum typestatus status; -#ifdef DBX_USE_BINCL int file_number; int type_number; -#endif }; /* Vector recording information about C data types. @@ -219,25 +166,23 @@ struct typeinfo we assign it a number using next_type_number. That is its index in this vector. */ -struct typeinfo *typevec; +static GTY ((length ("typevec_len"))) struct typeinfo *typevec; /* Number of elements of space allocated in `typevec'. */ -static int typevec_len; +static GTY(()) int typevec_len; /* In dbx output, each type gets a unique number. This is the number for the next type output. The number, once assigned, is in the TYPE_SYMTAB_ADDRESS field. */ -static int next_type_number; - -#ifdef DBX_USE_BINCL +static GTY(()) int next_type_number; /* When using N_BINCL in dbx output, each type number is actually a pair of the file number and the type number within the file. This is a stack of input files. */ -struct dbx_file +struct dbx_file GTY(()) { struct dbx_file *next; int file_number; @@ -246,13 +191,62 @@ struct dbx_file /* This is the top of the stack. */ -static struct dbx_file *current_file; +static GTY(()) struct dbx_file *current_file; /* This is the next file number to use. */ -static int next_file_number; +static GTY(()) int next_file_number; + +/* Typical USG systems don't have stab.h, and they also have + no use for DBX-format debugging info. */ + +#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) + +/* Nonzero if we have actually used any of the GDB extensions + to the debugging format. The idea is that we use them for the + first time only if there's a strong reason, but once we have done that, + we use them whenever convenient. */ + +static int have_used_extensions = 0; + +/* Number for the next N_SOL filename stabs label. The number 0 is reserved + for the N_SO filename stabs label. */ + +#if defined (DBX_DEBUGGING_INFO) && !defined (DBX_OUTPUT_SOURCE_FILENAME) +static int source_label_number = 1; +#endif + +#ifdef DEBUG_SYMS_TEXT +#define FORCE_TEXT function_section (current_function_decl); +#else +#define FORCE_TEXT +#endif + +#include "gstab.h" + +#define STAB_CODE_TYPE enum __stab_debug_code + +/* 1 if PARM is passed to this function in memory. */ + +#define PARM_PASSED_IN_MEMORY(PARM) \ + (GET_CODE (DECL_INCOMING_RTL (PARM)) == MEM) -#endif /* DBX_USE_BINCL */ +/* A C expression for the integer offset value of an automatic variable + (N_LSYM) having address X (an RTX). */ +#ifndef DEBUGGER_AUTO_OFFSET +#define DEBUGGER_AUTO_OFFSET(X) \ + (GET_CODE (X) == PLUS ? INTVAL (XEXP (X, 1)) : 0) +#endif + +/* A C expression for the integer offset value of an argument (N_PSYM) + having address X (an RTX). The nominal offset is OFFSET. */ +#ifndef DEBUGGER_ARG_OFFSET +#define DEBUGGER_ARG_OFFSET(OFFSET, X) (OFFSET) +#endif + +/* Stream for writing to assembler file. */ + +static FILE *asmfile; /* These variables are for dbxout_symbol to communicate to dbxout_finish_symbol. @@ -425,7 +419,7 @@ dbxout_init (input_file_name) asmfile = asm_out_file; typevec_len = 100; - typevec = (struct typeinfo *) xcalloc (typevec_len, sizeof typevec[0]); + typevec = (struct typeinfo *) ggc_calloc (typevec_len, sizeof typevec[0]); /* Convert Ltext into the appropriate format for local labels in case the system doesn't insert underscores in front of user generated @@ -484,7 +478,7 @@ dbxout_init (input_file_name) next_type_number = 1; #ifdef DBX_USE_BINCL - current_file = (struct dbx_file *) xmalloc (sizeof *current_file); + current_file = (struct dbx_file *) ggc_alloc (sizeof *current_file); current_file->next = NULL; current_file->file_number = 0; current_file->next_type_number = 1; @@ -541,7 +535,7 @@ dbxout_start_source_file (line, filename) const char *filename ATTRIBUTE_UNUSED; { #ifdef DBX_USE_BINCL - struct dbx_file *n = (struct dbx_file *) xmalloc (sizeof *n); + struct dbx_file *n = (struct dbx_file *) ggc_alloc (sizeof *n); n->next = current_file; n->file_number = next_file_number++; @@ -560,12 +554,8 @@ dbxout_end_source_file (line) unsigned int line ATTRIBUTE_UNUSED; { #ifdef DBX_USE_BINCL - struct dbx_file *next; - fprintf (asmfile, "%s%d,0,0,0\n", ASM_STABN_OP, N_EINCL); - next = current_file->next; - free (current_file); - current_file = next; + current_file = current_file->next; #endif } @@ -1149,8 +1139,9 @@ dbxout_type (type, full) if (next_type_number == typevec_len) { typevec - = (struct typeinfo *) xrealloc (typevec, - typevec_len * 2 * sizeof typevec[0]); + = (struct typeinfo *) ggc_realloc (typevec, + (typevec_len * 2 + * sizeof typevec[0])); memset ((char *) (typevec + typevec_len), 0, typevec_len * sizeof typevec[0]); typevec_len *= 2; @@ -3008,3 +2999,5 @@ dbxout_begin_function (decl) #endif /* DBX_DEBUGGING_INFO */ #endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */ + +#include "gt-dbxout.h" diff --git a/gcc/doc/cppopts.texi b/gcc/doc/cppopts.texi index 74fe8be..95311a8 100644 --- a/gcc/doc/cppopts.texi +++ b/gcc/doc/cppopts.texi @@ -301,6 +301,17 @@ a dependency output file as a side-effect of the compilation process. Like @option{-MD} except mention only user header files, not system -header files. +@ifclear cppmanual +@item -fpch-deps +@opindex fpch-deps +When using precompiled headers (@pxref{Precompiled Headers}), this flag +will cause the dependency-output flags to also list the files from the +precompiled header's dependencies. If not specified only the +precompiled header would be listed and not the files that were used to +create it because those files are not consulted when a precompiled +header is used. + +@end ifclear @item -x c @itemx -x c++ @itemx -x objective-c diff --git a/gcc/doc/gty.texi b/gcc/doc/gty.texi index 55deef2..ed7d3d2 100644 --- a/gcc/doc/gty.texi +++ b/gcc/doc/gty.texi @@ -10,7 +10,8 @@ GCC uses some fairly sophisticated memory management techniques, which involve determining information about GCC's data structures from GCC's -source code and using this information to perform garbage collection. +source code and using this information to perform garbage collection and +implement precompiled headers. A full C parser would be too overcomplicated for this task, so a limited subset of C is interpreted and special markers are used to determine @@ -227,6 +228,39 @@ this field is always @code{NULL}. This is used to avoid requiring backends to define certain optional structures. It doesn't work with language frontends. +@findex chain_next +@findex chain_prev +@item chain_next +@itemx chain_prev + +It's helpful for the type machinery to know if objects are often +chained together in long lists; this lets it generate code that uses +less stack space by iterating along the list instead of recursing down +it. @code{chain_next} is an expression for the next item in the list, +@code{chain_prev} is an expression for the previous item. The +machinery requires that taking the next item of the previous item +gives the original item. + +@findex reorder +@item reorder + +Some data structures depend on the relative ordering of pointers. If +the type machinery needs to change that ordering, it will call the +function referenced by the @code{reorder} option, before changing the +pointers in the object that's pointed to by the field the option +applies to. The function must be of the type @code{void ()(void *, +void *, gt_pointer_operator, void *)}. The second parameter is the +pointed-to object; the third parameter is a routine that, given a +pointer, can update it to its new value. The fourth parameter is a +cookie to be passed to the third parameter. The first parameter is +the structure that contains the object, or the object itself if it is +a structure. + +No data structure may depend on the absolute value of pointers. Even +relying on relative orderings and using @code{reorder} functions can +be expensive. It is better to depend on properties of the data, like +an ID number or the hash of a string instead. + @findex special @item special diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 8b3e365..bfbdd3e 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -141,6 +141,7 @@ only one of these two forms, whichever one is not the default. * Code Gen Options:: Specifying conventions for function calls, data layout and register usage. * Environment Variables:: Env vars that affect GCC. +* Precompiled Headers:: Compiling a header once, and using it many times. * Running Protoize:: Automatically adding or removing function prototypes. @end menu @@ -220,7 +221,7 @@ in the following sections. -Wimplicit -Wimplicit-int @gol -Wimplicit-function-declaration @gol -Werror-implicit-function-declaration @gol --Wimport -Winline -Wno-endif-labels @gol +-Wimport -Winline -Winvalid-pch -Wno-endif-labels @gol -Wlarger-than-@var{len} -Wlong-long @gol -Wmain -Wmissing-braces @gol -Wmissing-format-attribute -Wmissing-noreturn @gol @@ -767,7 +768,7 @@ Objective-C source code. Note that you must link with the library Objective-C source code which should not be preprocessed. @item @var{file}.h -C header file (not to be compiled or linked). +C or C++ header file to be turned into a precompiled header. @item @var{file}.cc @itemx @var{file}.cp @@ -780,6 +781,10 @@ C++ source code which must be preprocessed. Note that in @samp{.cxx}, the last two letters must both be literally @samp{x}. Likewise, @samp{.C} refers to a literal capital C@. +@item @var{file}.hh +@itemx @var{file}.H +C++ header file to be turned into a precompiled header. + @item @var{file}.f @itemx @var{file}.for @itemx @var{file}.FOR @@ -843,7 +848,7 @@ name suffix). This option applies to all following input files until the next @option{-x} option. Possible values for @var{language} are: @example c c-header cpp-output -c++ c++-cpp-output +c++ c++-header c++-cpp-output objective-c objc-cpp-output assembler assembler-with-cpp ada @@ -965,22 +970,24 @@ Display the version number and copyrights of the invoked GCC. @cindex suffixes for C++ source @cindex C++ source file suffixes C++ source files conventionally use one of the suffixes @samp{.C}, -@samp{.cc}, @samp{.cpp}, @samp{.CPP}, @samp{.c++}, @samp{.cp}, or @samp{.cxx}; +@samp{.cc}, @samp{.cpp}, @samp{.CPP}, @samp{.c++}, @samp{.cp}, or +@samp{.cxx}; C++ header files often use @samp{.hh} or @samp{.H}; and preprocessed C++ files use the suffix @samp{.ii}. GCC recognizes files with these names and compiles them as C++ programs even if you -call the compiler the same way as for compiling C programs (usually with -the name @command{gcc}). +call the compiler the same way as for compiling C programs (usually +with the name @command{gcc}). @findex g++ @findex c++ However, C++ programs often require class libraries as well as a compiler that understands the C++ language---and under some -circumstances, you might want to compile programs from standard input, -or otherwise without a suffix that flags them as C++ programs. -@command{g++} is a program that calls GCC with the default language -set to C++, and automatically specifies linking against the C++ -library. On many systems, @command{g++} is also -installed with the name @command{c++}. +circumstances, you might want to compile programs or header files from +standard input, or otherwise without a suffix that flags them as C++ +programs. You might also like to precompile a C header file with a +@samp{.h} extension to be used in C++ compilations. @command{g++} is a +program that calls GCC with the default language set to C++, and +automatically specifies linking against the C++ library. On many +systems, @command{g++} is also installed with the name @command{c++}. @cindex invoking @command{g++} When you compile C++ programs, you may specify many of the same @@ -2800,6 +2807,11 @@ code is to provide behavior which is selectable at compile-time. @opindex Winline Warn if a function can not be inlined and it was declared as inline. +@item -Winvalid-pch +@opindex Winvalid-pch +Warn if a precompiled header (@pxref{Precompiled Headers}) is found in +the search path but can't be used. + @item -Wlong-long @opindex Wlong-long @opindex Wno-long-long @@ -10924,6 +10936,104 @@ preprocessor. @c man end +@node Precompiled Headers +@section Using Precompiled Headers +@cindex precompiled headers +@cindex speed of compilation + +Often large projects have many header files that are included in every +source file. The time the compiler takes to process these header files +over and over again can account for nearly all of the time required to +build the project. To make builds faster, GCC allows users to +`precompile' a header file; then, if builds can use the precompiled +header file they will be much faster. + +To create a precompiled header file, simply compile it as you would any +other file, if necessary using the @option{-x} option to make the driver +treat it as a C or C++ header file. You will probably want to use a +tool like @command{make} to keep the precompiled header up-to-date when +the headers it contains change. + +A precompiled header file will be searched for when @code{#include} is +seen in the compilation. As it searches for the included file +(@pxref{Search Path,,Search Path,cpp.info,The C Preprocessor}) the +compiler looks for a precompiled header in each directory just before it +looks for the include file in that directory. The name searched for is +the name specified in the @code{#include} with @samp{.pch} appended. If +the precompiled header file can't be used, it is ignored. + +For instance, if you have @code{#include "all.h"}, and you have +@file{all.h.pch} in the same directory as @file{all.h}, then the +precompiled header file will be used if possible, and the original +header will be used otherwise. + +Alternatively, you might decide to put the precompiled header file in a +directory and use @option{-I} to ensure that directory is searched +before (or instead of) the directory containing the original header. +Then, if you want to check that the precompiled header file is always +used, you can put a file of the same name as the original header in this +directory containing an @code{#error} command. + +This also works with @option{-include}. So yet another way to use +precompiled headers, good for projects not designed with precompiled +header files in mind, is to simply take most of the header files used by +a project, include them from another header file, precompile that header +file, and @option{-include} the precompiled header. If the header files +have guards against multiple inclusion, they will be skipped because +they've already been included (in the precompiled header). + +If you need to precompile the same header file for different +languages, targets, or compiler options, you can instead make a +@emph{directory} named like @file{all.h.pch}, and put each precompiled +header in the directory. (It doesn't matter what you call the files +in the directory, every precompiled header in the directory will be +considered.) The first precompiled header encountered in the +directory that is valid for this compilation will be used; they're +searched in no particular order. + +There are many other possibilities, limited only by your imagination, +good sense, and the constraints of your build system. + +A precompiled header file can be used only when these conditions apply: + +@itemize +@item +Only one precompiled header can be used in a particular compilation. +@item +A precompiled header can't be used once the first C token is seen. You +can have preprocessor directives before a precompiled header; you can +even include a precompiled header from inside another header, so long as +there are no C tokens before the @code{#include}. +@item +The precompiled header file must be produced for the same language as +the current compilation. You can't use a C precompiled header for a C++ +compilation. +@item +The precompiled header file must be produced by the same compiler +version and configuration as the current compilation is using. +The easiest way to guarantee this is to use the same compiler binary +for creating and using precompiled headers. +@item +Any macros defined before the precompiled header (including with +@option{-D}) must either be defined in the same way as when the +precompiled header was generated, or must not affect the precompiled +header, which usually means that the they don't appear in the +precompiled header at all. +@item +Certain command-line options must be defined in the same way as when the +precompiled header was generated. At present, it's not clear which +options are safe to change and which are not; the safest choice is to +use exactly the same options when generating and using the precompiled +header. +@end itemize + +For all of these but the last, the compiler will automatically ignore +the precompiled header if the conditions aren't met. For the last item, +some option changes will cause the precompiled header to be rejected, +but not all incompatible option combinations have yet been found. If +you find a new incompatible combination, please consider filing a bug +report, see @ref{Bugs}. + @node Running Protoize @section Running Protoize diff --git a/gcc/doc/passes.texi b/gcc/doc/passes.texi index c47433e..8a96a69 100644 --- a/gcc/doc/passes.texi +++ b/gcc/doc/passes.texi @@ -1,4 +1,4 @@ -@c Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, +@c Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2002, @c 1999, 2000, 2001 Free Software Foundation, Inc. @c This is part of the GCC manual. @c For copying conditions, see the file gcc.texi. @@ -73,54 +73,22 @@ performed by cpplib, which is covered in separate documentation. In particular, the internals are covered in @xref{Top, ,Cpplib internals, cppinternals, Cpplib Internals}. -@c Avoiding overfull is tricky here. -The source files to parse C are -@file{c-convert.c}, -@file{c-decl.c}, -@file{c-errors.c}, -@file{c-lang.c}, -@file{c-objc-common.c}, -@file{c-parse.in}, -@file{c-aux-info.c}, -and -@file{c-typeck.c}, -along with a header file -@file{c-tree.h} -and some files shared with Objective-C and C++. - -The source files for parsing C++ are in @file{cp/}. -They are @file{parse.y}, -@file{class.c}, -@file{cvt.c}, @file{decl.c}, @file{decl2.c}, -@file{except.c}, -@file{expr.c}, @file{init.c}, @file{lex.c}, -@file{method.c}, @file{ptree.c}, -@file{search.c}, @file{spew.c}, -@file{semantics.c}, @file{tree.c}, -@file{typeck2.c}, and -@file{typeck.c}, along with header files @file{cp-tree.def}, -@file{cp-tree.h}, and @file{decl.h}. - -The special source files for parsing Objective-C are in @file{objc/}. -They are @file{objc-act.c}, @file{objc-tree.def}, and @file{objc-act.h}. -Certain C-specific files are used for this as well. - -The files -@file{c-common.c}, +The source files to parse C are found in the toplevel directory, and +by convention are named @file{c-*}. Some of these are also used by +the other C-like languages: @file{c-common.c}, @file{c-common.def}, @file{c-format.c}, @file{c-opts.c}, @file{c-pragma.c}, @file{c-semantics.c}, -and @file{c-lex.c}, -along with header files @file{c-common.h}, @file{c-dump.h}, and @file{c-pragma.h}, -are also used for all of the above languages. +Files specific to each language are in subdirectories named after the +language in question, like @file{ada}, @file{objc}, @file{cp} (for C++). @cindex Tree optimization @item diff --git a/gcc/dwarf2asm.c b/gcc/dwarf2asm.c index 777ba8da..396c2cd 100644 --- a/gcc/dwarf2asm.c +++ b/gcc/dwarf2asm.c @@ -688,12 +688,12 @@ dw2_asm_output_delta_sleb128 VPARAMS ((const char *lab1 ATTRIBUTE_UNUSED, VA_CLOSE (ap); } -static int mark_indirect_pool_entry PARAMS ((splay_tree_node, void *)); -static void mark_indirect_pool PARAMS ((PTR arg)); static rtx dw2_force_const_mem PARAMS ((rtx)); static int dw2_output_indirect_constant_1 PARAMS ((splay_tree_node, void *)); -static splay_tree indirect_pool; +static GTY((param1_is (char *), param2_is (tree))) splay_tree indirect_pool; + +static GTY(()) int dw2_const_labelno; #if defined(HAVE_GAS_HIDDEN) && defined(SUPPORTS_ONE_ONLY) # define USE_LINKONCE_INDIRECT 1 @@ -701,26 +701,6 @@ static splay_tree indirect_pool; # define USE_LINKONCE_INDIRECT 0 #endif -/* Mark all indirect constants for GC. */ - -static int -mark_indirect_pool_entry (node, data) - splay_tree_node node; - void* data ATTRIBUTE_UNUSED; -{ - ggc_mark_tree ((tree) node->value); - return 0; -} - -/* Mark all indirect constants for GC. */ - -static void -mark_indirect_pool (arg) - PTR arg ATTRIBUTE_UNUSED; -{ - splay_tree_foreach (indirect_pool, mark_indirect_pool_entry, NULL); -} - /* Put X, a SYMBOL_REF, in memory. Return a SYMBOL_REF to the allocated memory. Differs from force_const_mem in that a single pool is used for the entire unit of translation, and the memory is not guaranteed to be @@ -735,10 +715,7 @@ dw2_force_const_mem (x) tree decl; if (! indirect_pool) - { - indirect_pool = splay_tree_new (splay_tree_compare_pointers, NULL, NULL); - ggc_add_root (&indirect_pool, 1, sizeof indirect_pool, mark_indirect_pool); - } + indirect_pool = splay_tree_new_ggc (splay_tree_compare_pointers); if (GET_CODE (x) != SYMBOL_REF) abort (); @@ -765,11 +742,10 @@ dw2_force_const_mem (x) } else { - extern int const_labelno; char label[32]; - ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno); - ++const_labelno; + ASM_GENERATE_INTERNAL_LABEL (label, "LDFCM", dw2_const_labelno); + ++dw2_const_labelno; id = get_identifier (label); decl = build_decl (VAR_DECL, id, ptr_type_node); DECL_ARTIFICIAL (decl) = 1; @@ -906,3 +882,5 @@ dw2_asm_output_encoded_addr_rtx VPARAMS ((int encoding, VA_CLOSE (ap); } + +#include "gt-dwarf2asm.h" diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index c931420..38d3400 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -63,7 +63,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "debug.h" #include "target.h" #include "langhooks.h" -#include "hashtable.h" #include "hashtab.h" #ifdef DWARF2_DEBUGGING_INFO @@ -163,8 +162,6 @@ static GTY(()) varray_type incomplete_types; define type declaration DIE's. */ static GTY(()) varray_type decl_scope_table; -#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO) - /* How to start an assembler comment. */ #ifndef ASM_COMMENT_START #define ASM_COMMENT_START ";#" @@ -179,21 +176,31 @@ typedef union dw_cfi_oprnd_struct *dw_cfi_oprnd_ref; and address fields are provided as possible operands; their use is selected by the opcode field. */ -typedef union dw_cfi_oprnd_struct +enum dw_cfi_oprnd_type { + dw_cfi_oprnd_unused, + dw_cfi_oprnd_reg_num, + dw_cfi_oprnd_offset, + dw_cfi_oprnd_addr, + dw_cfi_oprnd_loc +}; + +typedef union dw_cfi_oprnd_struct GTY(()) { - unsigned long dw_cfi_reg_num; - long int dw_cfi_offset; - const char *dw_cfi_addr; - struct dw_loc_descr_struct *dw_cfi_loc; + unsigned long GTY ((tag ("dw_cfi_oprnd_reg_num"))) dw_cfi_reg_num; + long int GTY ((tag ("dw_cfi_oprnd_offset"))) dw_cfi_offset; + const char * GTY ((tag ("dw_cfi_oprnd_addr"))) dw_cfi_addr; + struct dw_loc_descr_struct * GTY ((tag ("dw_cfi_oprnd_loc"))) dw_cfi_loc; } dw_cfi_oprnd; -typedef struct dw_cfi_struct +typedef struct dw_cfi_struct GTY(()) { dw_cfi_ref dw_cfi_next; enum dwarf_call_frame_info dw_cfi_opc; - dw_cfi_oprnd dw_cfi_oprnd1; - dw_cfi_oprnd dw_cfi_oprnd2; + dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd1_desc (%1.dw_cfi_opc)"))) + dw_cfi_oprnd1; + dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd2_desc (%1.dw_cfi_opc)"))) + dw_cfi_oprnd2; } dw_cfi_node; @@ -202,7 +209,7 @@ dw_cfi_node; It can now be either REG + CFA_OFFSET or *(REG + BASE_OFFSET) + CFA_OFFSET. Instead of passing around REG and OFFSET, we pass a copy of this structure. */ -typedef struct cfa_loc +typedef struct cfa_loc GTY(()) { unsigned long reg; long offset; @@ -216,7 +223,7 @@ typedef struct cfa_loc CIE obviates the need to keep track of multiple CIE's in the DWARF generation routines below. */ -typedef struct dw_fde_struct +typedef struct dw_fde_struct GTY(()) { const char *dw_fde_begin; const char *dw_fde_current_label; @@ -267,7 +274,7 @@ dw_fde_node; /* A pointer to the base of a table that contains frame description information for each routine. */ -static dw_fde_ref fde_table; +static GTY((length ("fde_table_allocated"))) dw_fde_ref fde_table; /* Number of elements currently allocated for fde_table. */ static unsigned fde_table_allocated; @@ -280,7 +287,7 @@ static unsigned fde_table_in_use; #define FDE_TABLE_INCREMENT 256 /* A list of call frame insns for the CIE. */ -static dw_cfi_ref cie_cfi_head; +static GTY(()) dw_cfi_ref cie_cfi_head; /* Some DWARF extensions (e.g., MIPS/SGI) implement a subprogram attribute that accelerates the lookup of the FDE associated @@ -288,16 +295,20 @@ static dw_cfi_ref cie_cfi_head; associated with the current function (body) definition. */ static unsigned current_funcdef_fde; -struct ht *debug_str_hash; - -struct indirect_string_node +struct indirect_string_node GTY(()) { - struct ht_identifier id; + const char *str; unsigned int refcount; unsigned int form; char *label; }; +static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash; + +static GTY(()) int dw2_string_counter; + +#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO) + /* Forward declarations for functions defined in this file. */ static char *stripattributes PARAMS ((const char *)); @@ -313,6 +324,10 @@ static void reg_save PARAMS ((const char *, unsigned, static void initial_return_save PARAMS ((rtx)); static long stack_adjust_offset PARAMS ((rtx)); static void output_cfi PARAMS ((dw_cfi_ref, dw_fde_ref, int)); +static enum dw_cfi_oprnd_type dw_cfi_oprnd1_desc + PARAMS ((enum dwarf_call_frame_info cfi)); +static enum dw_cfi_oprnd_type dw_cfi_oprnd2_desc + PARAMS ((enum dwarf_call_frame_info cfi)); static void output_call_frame_info PARAMS ((int)); static void dwarf2out_stack_adjust PARAMS ((rtx)); static void queue_reg_save PARAMS ((const char *, rtx, long)); @@ -515,7 +530,7 @@ dwarf_cfi_name (cfi_opc) static inline dw_cfi_ref new_cfi () { - dw_cfi_ref cfi = (dw_cfi_ref) xmalloc (sizeof (dw_cfi_node)); + dw_cfi_ref cfi = (dw_cfi_ref) ggc_alloc (sizeof (dw_cfi_node)); cfi->dw_cfi_next = NULL; cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0; @@ -1086,18 +1101,22 @@ dwarf2out_stack_adjust (insn) dwarf2out_args_size (label, args_size); } +#endif + /* We delay emitting a register save until either (a) we reach the end of the prologue or (b) the register is clobbered. This clusters register saves so that there are fewer pc advances. */ -struct queued_reg_save +struct queued_reg_save GTY(()) { struct queued_reg_save *next; rtx reg; long cfa_offset; }; -static struct queued_reg_save *queued_reg_saves; +static GTY(()) struct queued_reg_save *queued_reg_saves; + +#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO) static const char *last_reg_save_label; static void @@ -1106,7 +1125,7 @@ queue_reg_save (label, reg, offset) rtx reg; long offset; { - struct queued_reg_save *q = (struct queued_reg_save *) xmalloc (sizeof (*q)); + struct queued_reg_save *q = ggc_alloc (sizeof (*q)); q->next = queued_reg_saves; q->reg = reg; @@ -1125,7 +1144,6 @@ flush_queued_reg_saves () { dwarf2out_reg_save (last_reg_save_label, REGNO (q->reg), q->cfa_offset); next = q->next; - free (q); } queued_reg_saves = NULL; @@ -1678,6 +1696,78 @@ dwarf2out_frame_debug (insn) dwarf2out_frame_debug_expr (insn, label); } +#endif + +/* Describe for the GTY machinery what parts of dw_cfi_oprnd1 are used. */ + +static enum dw_cfi_oprnd_type +dw_cfi_oprnd1_desc (cfi) + enum dwarf_call_frame_info cfi; +{ + switch (cfi) + { + case DW_CFA_nop: + case DW_CFA_GNU_window_save: + return dw_cfi_oprnd_unused; + + case DW_CFA_set_loc: + case DW_CFA_advance_loc1: + case DW_CFA_advance_loc2: + case DW_CFA_advance_loc4: + case DW_CFA_MIPS_advance_loc8: + return dw_cfi_oprnd_addr; + + case DW_CFA_offset: + case DW_CFA_offset_extended: + case DW_CFA_def_cfa: + case DW_CFA_offset_extended_sf: + case DW_CFA_def_cfa_sf: + case DW_CFA_restore_extended: + case DW_CFA_undefined: + case DW_CFA_same_value: + case DW_CFA_def_cfa_register: + case DW_CFA_register: + return dw_cfi_oprnd_reg_num; + + case DW_CFA_def_cfa_offset: + case DW_CFA_GNU_args_size: + case DW_CFA_def_cfa_offset_sf: + return dw_cfi_oprnd_offset; + + case DW_CFA_def_cfa_expression: + case DW_CFA_expression: + return dw_cfi_oprnd_loc; + + default: + abort (); + } +} + +/* Describe for the GTY machinery what parts of dw_cfi_oprnd2 are used. */ + +static enum dw_cfi_oprnd_type +dw_cfi_oprnd2_desc (cfi) + enum dwarf_call_frame_info cfi; +{ + switch (cfi) + { + case DW_CFA_def_cfa: + case DW_CFA_def_cfa_sf: + case DW_CFA_offset: + case DW_CFA_offset_extended_sf: + case DW_CFA_offset_extended: + return dw_cfi_oprnd_offset; + + case DW_CFA_register: + return dw_cfi_oprnd_reg_num; + + default: + return dw_cfi_oprnd_unused; + } +} + +#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO) + /* Output a Call Frame Information opcode and its operand(s). */ static void @@ -2118,9 +2208,10 @@ dwarf2out_begin_prologue (line, file) if (fde_table_in_use == fde_table_allocated) { fde_table_allocated += FDE_TABLE_INCREMENT; - fde_table - = (dw_fde_ref) xrealloc (fde_table, - fde_table_allocated * sizeof (dw_fde_node)); + fde_table = ggc_realloc (fde_table, + fde_table_allocated * sizeof (dw_fde_node)); + memset (fde_table + fde_table_in_use, 0, + FDE_TABLE_INCREMENT * sizeof (dw_fde_node)); } /* Record the FDE associated with this function. */ @@ -2172,7 +2263,8 @@ void dwarf2out_frame_init () { /* Allocate the initial hunk of the fde_table. */ - fde_table = (dw_fde_ref) xcalloc (FDE_TABLE_INCREMENT, sizeof (dw_fde_node)); + fde_table = (dw_fde_ref) ggc_alloc_cleared (FDE_TABLE_INCREMENT + * sizeof (dw_fde_node)); fde_table_allocated = FDE_TABLE_INCREMENT; fde_table_in_use = 0; @@ -2196,6 +2288,7 @@ dwarf2out_frame_finish () if (! USING_SJLJ_EXCEPTIONS && (flag_unwind_tables || flag_exceptions)) output_call_frame_info (1); } +#endif /* And now, the subset of the debugging information support code necessary for emitting location expressions. */ @@ -2214,7 +2307,7 @@ typedef struct dw_loc_list_struct *dw_loc_list_ref; can take on several forms. The forms that are used in this implementation are listed below. */ -typedef enum +enum dw_val_class { dw_val_class_addr, dw_val_class_offset, @@ -2231,13 +2324,12 @@ typedef enum dw_val_class_lbl_id, dw_val_class_lbl_offset, dw_val_class_str -} -dw_val_class; +}; /* Describe a double word constant value. */ /* ??? Every instance of long_long in the code really means CONST_DOUBLE. */ -typedef struct dw_long_long_struct +typedef struct dw_long_long_struct GTY(()) { unsigned long hi; unsigned long low; @@ -2246,9 +2338,9 @@ dw_long_long_const; /* Describe a floating point constant value. */ -typedef struct dw_fp_struct +typedef struct dw_fp_struct GTY(()) { - long *array; + long * GTY((length ("%h.length"))) array; unsigned length; } dw_float_const; @@ -2256,37 +2348,37 @@ dw_float_const; /* The dw_val_node describes an attribute's value, as it is represented internally. */ -typedef struct dw_val_struct +typedef struct dw_val_struct GTY(()) { - dw_val_class val_class; - union + enum dw_val_class val_class; + union dw_val_struct_union { - rtx val_addr; - long unsigned val_offset; - dw_loc_list_ref val_loc_list; - dw_loc_descr_ref val_loc; - long int val_int; - long unsigned val_unsigned; - dw_long_long_const val_long_long; - dw_float_const val_float; - struct + rtx GTY ((tag ("dw_val_class_addr"))) val_addr; + long unsigned GTY ((tag ("dw_val_class_offset"))) val_offset; + dw_loc_list_ref GTY ((tag ("dw_val_class_loc_list"))) val_loc_list; + dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc; + long int GTY ((default (""))) val_int; + long unsigned GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned; + dw_long_long_const GTY ((tag ("dw_val_class_long_long"))) val_long_long; + dw_float_const GTY ((tag ("dw_val_class_float"))) val_float; + struct dw_val_die_union { dw_die_ref die; int external; - } val_die_ref; - unsigned val_fde_index; - struct indirect_string_node *val_str; - char *val_lbl_id; - unsigned char val_flag; + } GTY ((tag ("dw_val_class_die_ref"))) val_die_ref; + unsigned GTY ((tag ("dw_val_class_fde_ref"))) val_fde_index; + struct indirect_string_node * GTY ((tag ("dw_val_class_str"))) val_str; + char * GTY ((tag ("dw_val_class_lbl_id"))) val_lbl_id; + unsigned char GTY ((tag ("dw_val_class_flag"))) val_flag; } - v; + GTY ((desc ("%1.val_class"))) v; } dw_val_node; /* Locations in memory are described using a sequence of stack machine operations. */ -typedef struct dw_loc_descr_struct +typedef struct dw_loc_descr_struct GTY(()) { dw_loc_descr_ref dw_loc_next; enum dwarf_location_atom dw_loc_opc; @@ -2299,7 +2391,7 @@ dw_loc_descr_node; /* Location lists are ranges + location descriptions for that range, so you can track variables that are in different places over their entire life. */ -typedef struct dw_loc_list_struct +typedef struct dw_loc_list_struct GTY(()) { dw_loc_list_ref dw_loc_next; const char *begin; /* Label for begin address of range */ @@ -2310,6 +2402,8 @@ typedef struct dw_loc_list_struct dw_loc_descr_ref expr; } dw_loc_list_node; +#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO) + static const char *dwarf_stack_op_name PARAMS ((unsigned)); static dw_loc_descr_ref new_loc_descr PARAMS ((enum dwarf_location_atom, unsigned long, @@ -2645,10 +2739,8 @@ new_loc_descr (op, oprnd1, oprnd2) unsigned long oprnd1; unsigned long oprnd2; { - /* Use xcalloc here so we clear out all of the long_long constant in - the union. */ dw_loc_descr_ref descr - = (dw_loc_descr_ref) xcalloc (1, sizeof (dw_loc_descr_node)); + = (dw_loc_descr_ref) ggc_alloc_cleared (sizeof (dw_loc_descr_node)); descr->dw_loc_opc = op; descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const; @@ -3134,10 +3226,7 @@ get_cfa_from_loc_descr (cfa, loc) #ifdef DWARF2_DEBUGGING_INFO /* .debug_str support. */ -static hashnode indirect_string_alloc PARAMS ((hash_table *)); -static int output_indirect_string PARAMS ((struct cpp_reader *, - hashnode, const PTR)); - +static int output_indirect_string PARAMS ((void **, void *)); static void dwarf2out_init PARAMS ((const char *)); static void dwarf2out_finish PARAMS ((const char *)); @@ -3179,6 +3268,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = dwarf2out_abstract_function, /* outlining_inline_function */ debug_nothing_rtx /* label */ }; +#endif /* NOTE: In the comments in this file, many references are made to "Debugging Information Entries". This term is abbreviated as `DIE' @@ -3207,7 +3297,7 @@ typedef struct dw_ranges_struct *dw_ranges_ref; entry. The label gives the PC value associated with the line number entry. */ -typedef struct dw_line_info_struct +typedef struct dw_line_info_struct GTY(()) { unsigned long dw_file_num; unsigned long dw_line_num; @@ -3216,7 +3306,7 @@ dw_line_info_entry; /* Line information for functions in separate sections; each one gets its own sequence. */ -typedef struct dw_separate_line_info_struct +typedef struct dw_separate_line_info_struct GTY(()) { unsigned long dw_file_num; unsigned long dw_line_num; @@ -3228,7 +3318,7 @@ dw_separate_line_info_entry; a link to the next attribute in the chain, and an attribute value. Attributes are typically linked below the DIE they modify. */ -typedef struct dw_attr_struct +typedef struct dw_attr_struct GTY(()) { enum dwarf_attribute dw_attr; dw_attr_ref dw_attr_next; @@ -3238,7 +3328,7 @@ dw_attr_node; /* The Debugging Information Entry (DIE) structure */ -typedef struct die_struct +typedef struct die_struct GTY(()) { enum dwarf_tag die_tag; char *die_symbol; @@ -3254,20 +3344,20 @@ die_node; /* The pubname structure */ -typedef struct pubname_struct +typedef struct pubname_struct GTY(()) { dw_die_ref die; char *name; } pubname_entry; -struct dw_ranges_struct +struct dw_ranges_struct GTY(()) { int block_num; }; /* The limbo die list structure. */ -typedef struct limbo_die_struct +typedef struct limbo_die_struct GTY(()) { dw_die_ref die; tree created_for; @@ -3351,14 +3441,14 @@ limbo_die_node; static unsigned long next_die_offset; /* Record the root of the DIE's built for the current compilation unit. */ -static dw_die_ref comp_unit_die; +static GTY(()) dw_die_ref comp_unit_die; /* We need special handling in dwarf2out_start_source_file if it is first one. */ static int is_main_source; /* A list of DIEs with a NULL parent waiting to be relocated. */ -static limbo_die_node *limbo_die_list = 0; +static GTY(()) limbo_die_node *limbo_die_list; /* Structure used by lookup_filename to manage sets of filenames. */ struct file_table @@ -3379,7 +3469,7 @@ static struct file_table file_table; /* A pointer to the base of a table of references to DIE's that describe declarations. The table is indexed by DECL_UID() which is a unique number identifying each decl. */ -static dw_die_ref *decl_die_table; +static GTY((length ("decl_die_table_allocated"))) dw_die_ref *decl_die_table; /* Number of elements currently allocated for the decl_die_table. */ static unsigned decl_die_table_allocated; @@ -3394,7 +3484,8 @@ static unsigned decl_die_table_in_use; /* A pointer to the base of a list of references to DIE's that are uniquely identified by their tag, presence/absence of children DIE's, and list of attribute/value pairs. */ -static dw_die_ref *abbrev_die_table; +static GTY((length ("abbrev_die_table_allocated"))) + dw_die_ref *abbrev_die_table; /* Number of elements currently allocated for abbrev_die_table. */ static unsigned abbrev_die_table_allocated; @@ -3408,23 +3499,25 @@ static unsigned abbrev_die_table_in_use; /* A pointer to the base of a table that contains line information for each source code line in .text in the compilation unit. */ -static dw_line_info_ref line_info_table; +static GTY((length ("line_info_table_allocated"))) + dw_line_info_ref line_info_table; /* Number of elements currently allocated for line_info_table. */ static unsigned line_info_table_allocated; -/* Number of elements in separate_line_info_table currently in use. */ -static unsigned separate_line_info_table_in_use; +/* Number of elements in line_info_table currently in use. */ +static unsigned line_info_table_in_use; /* A pointer to the base of a table that contains line information for each source code line outside of .text in the compilation unit. */ -static dw_separate_line_info_ref separate_line_info_table; +static GTY ((length ("separate_line_info_table_allocated"))) + dw_separate_line_info_ref separate_line_info_table; /* Number of elements currently allocated for separate_line_info_table. */ static unsigned separate_line_info_table_allocated; -/* Number of elements in line_info_table currently in use. */ -static unsigned line_info_table_in_use; +/* Number of elements in separate_line_info_table currently in use. */ +static unsigned separate_line_info_table_in_use; /* Size (in elements) of increments by which we may expand the line_info_table. */ @@ -3432,7 +3525,7 @@ static unsigned line_info_table_in_use; /* A pointer to the base of a table that contains a list of publicly accessible names. */ -static pubname_ref pubname_table; +static GTY ((length ("pubname_table_allocated"))) pubname_ref pubname_table; /* Number of elements currently allocated for pubname_table. */ static unsigned pubname_table_allocated; @@ -3445,7 +3538,7 @@ static unsigned pubname_table_in_use; #define PUBNAME_TABLE_INCREMENT 64 /* Array of dies for which we should generate .debug_arange info. */ -static dw_die_ref *arange_table; +static GTY((length ("arange_table_allocated"))) dw_die_ref *arange_table; /* Number of elements currently allocated for arange_table. */ static unsigned arange_table_allocated; @@ -3458,7 +3551,7 @@ static unsigned arange_table_in_use; #define ARANGE_TABLE_INCREMENT 64 /* Array of dies for which we should generate .debug_ranges info. */ -static dw_ranges_ref ranges_table; +static GTY ((length ("ranges_table_allocated"))) dw_ranges_ref ranges_table; /* Number of elements currently allocated for ranges_table. */ static unsigned ranges_table_allocated; @@ -3479,6 +3572,8 @@ static int current_function_has_inlines; static int comp_unit_has_inlines; #endif +#ifdef DWARF2_DEBUGGING_INFO + /* Forward declarations for functions defined in this file. */ static int is_pseudo_reg PARAMS ((rtx)); @@ -3494,7 +3589,7 @@ static tree decl_ultimate_origin PARAMS ((tree)); static tree block_ultimate_origin PARAMS ((tree)); static tree decl_class_context PARAMS ((tree)); static void add_dwarf_attr PARAMS ((dw_die_ref, dw_attr_ref)); -static inline dw_val_class AT_class PARAMS ((dw_attr_ref)); +static inline enum dw_val_class AT_class PARAMS ((dw_attr_ref)); static void add_AT_flag PARAMS ((dw_die_ref, enum dwarf_attribute, unsigned)); @@ -3513,6 +3608,8 @@ static void add_AT_long_long PARAMS ((dw_die_ref, static void add_AT_float PARAMS ((dw_die_ref, enum dwarf_attribute, unsigned, long *)); +static hashval_t debug_str_do_hash PARAMS ((const void *)); +static int debug_str_eq PARAMS ((const void *, const void *)); static void add_AT_string PARAMS ((dw_die_ref, enum dwarf_attribute, const char *)); @@ -3737,7 +3834,6 @@ static void add_loc_descr_to_loc_list PARAMS ((dw_loc_list_ref *, const char *, const char *, const char *)); static void output_loc_list PARAMS ((dw_loc_list_ref)); static char *gen_internal_sym PARAMS ((const char *)); -static void mark_limbo_die_list PARAMS ((void *)); /* Section names used to hold DWARF debugging information. */ #ifndef DEBUG_INFO_SECTION @@ -4404,7 +4500,7 @@ add_dwarf_attr (die, attr) } } -static inline dw_val_class +static inline enum dw_val_class AT_class (a) dw_attr_ref a; { @@ -4419,7 +4515,7 @@ add_AT_flag (die, attr_kind, flag) enum dwarf_attribute attr_kind; unsigned flag; { - dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); attr->dw_attr_next = NULL; attr->dw_attr = attr_kind; @@ -4446,7 +4542,7 @@ add_AT_int (die, attr_kind, int_val) enum dwarf_attribute attr_kind; long int int_val; { - dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); attr->dw_attr_next = NULL; attr->dw_attr = attr_kind; @@ -4473,7 +4569,7 @@ add_AT_unsigned (die, attr_kind, unsigned_val) enum dwarf_attribute attr_kind; unsigned long unsigned_val; { - dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); attr->dw_attr_next = NULL; attr->dw_attr = attr_kind; @@ -4501,7 +4597,7 @@ add_AT_long_long (die, attr_kind, val_hi, val_low) unsigned long val_hi; unsigned long val_low; { - dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); attr->dw_attr_next = NULL; attr->dw_attr = attr_kind; @@ -4520,7 +4616,7 @@ add_AT_float (die, attr_kind, length, array) unsigned length; long *array; { - dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); attr->dw_attr_next = NULL; attr->dw_attr = attr_kind; @@ -4530,6 +4626,24 @@ add_AT_float (die, attr_kind, length, array) add_dwarf_attr (die, attr); } +/* Hash and equality functions for debug_str_hash. */ + +static hashval_t +debug_str_do_hash (x) + const void * x; +{ + return htab_hash_string (((const struct indirect_string_node *)x)->str); +} + +static int +debug_str_eq (x1, x2) + const void * x1; + const void * x2; +{ + return strcmp ((((const struct indirect_string_node *)x1)->str), + (const char *)x2) == 0; +} + /* Add a string attribute value to a DIE. */ static inline void @@ -4538,18 +4652,20 @@ add_AT_string (die, attr_kind, str) enum dwarf_attribute attr_kind; const char *str; { - dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); struct indirect_string_node *node; + PTR *slot; if (! debug_str_hash) - { - debug_str_hash = ht_create (10); - debug_str_hash->alloc_node = indirect_string_alloc; - } - - node = (struct indirect_string_node *) - ht_lookup (debug_str_hash, (const unsigned char *) str, - strlen (str), HT_ALLOC); + debug_str_hash = htab_create_ggc (10, debug_str_do_hash, + debug_str_eq, NULL); + + slot = htab_find_slot_with_hash (debug_str_hash, str, + htab_hash_string (str), INSERT); + if (*slot == NULL) + *slot = ggc_alloc_cleared (sizeof (struct indirect_string_node)); + node = (struct indirect_string_node *) *slot; + node->str = ggc_alloc_string (str, -1); node->refcount++; attr->dw_attr_next = NULL; @@ -4564,7 +4680,7 @@ AT_string (a) dw_attr_ref a; { if (a && AT_class (a) == dw_val_class_str) - return (const char *) HT_STR (&a->dw_attr_val.v.val_str->id); + return a->dw_attr_val.v.val_str->str; abort (); } @@ -4580,14 +4696,13 @@ AT_string_form (a) { struct indirect_string_node *node; unsigned int len; - extern int const_labelno; char label[32]; node = a->dw_attr_val.v.val_str; if (node->form) return node->form; - len = HT_LEN (&node->id) + 1; + len = strlen (node->str) + 1; /* If the string is shorter or equal to the size of the reference, it is always better to put it inline. */ @@ -4601,8 +4716,8 @@ AT_string_form (a) && (len - DWARF_OFFSET_SIZE) * node->refcount <= len) return node->form = DW_FORM_string; - ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno); - ++const_labelno; + ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter); + ++dw2_string_counter; node->label = xstrdup (label); return node->form = DW_FORM_strp; @@ -4619,7 +4734,7 @@ add_AT_die_ref (die, attr_kind, targ_die) enum dwarf_attribute attr_kind; dw_die_ref targ_die; { - dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); attr->dw_attr_next = NULL; attr->dw_attr = attr_kind; @@ -4668,7 +4783,7 @@ add_AT_fde_ref (die, attr_kind, targ_fde) enum dwarf_attribute attr_kind; unsigned targ_fde; { - dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); attr->dw_attr_next = NULL; attr->dw_attr = attr_kind; @@ -4685,7 +4800,7 @@ add_AT_loc (die, attr_kind, loc) enum dwarf_attribute attr_kind; dw_loc_descr_ref loc; { - dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); attr->dw_attr_next = NULL; attr->dw_attr = attr_kind; @@ -4710,7 +4825,7 @@ add_AT_loc_list (die, attr_kind, loc_list) enum dwarf_attribute attr_kind; dw_loc_list_ref loc_list; { - dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); attr->dw_attr_next = NULL; attr->dw_attr = attr_kind; @@ -4738,7 +4853,7 @@ add_AT_addr (die, attr_kind, addr) enum dwarf_attribute attr_kind; rtx addr; { - dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); attr->dw_attr_next = NULL; attr->dw_attr = attr_kind; @@ -4765,7 +4880,7 @@ add_AT_lbl_id (die, attr_kind, lbl_id) enum dwarf_attribute attr_kind; const char *lbl_id; { - dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); attr->dw_attr_next = NULL; attr->dw_attr = attr_kind; @@ -4782,7 +4897,7 @@ add_AT_lbl_offset (die, attr_kind, label) enum dwarf_attribute attr_kind; const char *label; { - dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); attr->dw_attr_next = NULL; attr->dw_attr = attr_kind; @@ -4799,7 +4914,7 @@ add_AT_offset (die, attr_kind, offset) enum dwarf_attribute attr_kind; unsigned long offset; { - dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); attr->dw_attr_next = NULL; attr->dw_attr = attr_kind; @@ -4816,7 +4931,7 @@ add_AT_range_list (die, attr_kind, offset) enum dwarf_attribute attr_kind; unsigned long offset; { - dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); attr->dw_attr_next = NULL; attr->dw_attr = attr_kind; @@ -4976,27 +5091,9 @@ static inline void free_AT (a) dw_attr_ref a; { - switch (AT_class (a)) - { - case dw_val_class_str: - if (a->dw_attr_val.v.val_str->refcount) - a->dw_attr_val.v.val_str->refcount--; - break; - - case dw_val_class_lbl_id: - case dw_val_class_lbl_offset: - free (a->dw_attr_val.v.val_lbl_id); - break; - - case dw_val_class_float: - free (a->dw_attr_val.v.val_float.array); - break; - - default: - break; - } - - free (a); + if (AT_class (a) == dw_val_class_str) + if (a->dw_attr_val.v.val_str->refcount) + a->dw_attr_val.v.val_str->refcount--; } /* Remove the specified attribute if present. */ @@ -5031,7 +5128,6 @@ free_die (die) dw_die_ref die; { remove_children (die); - free (die); } /* Discard the children of this DIE. */ @@ -5124,7 +5220,7 @@ new_die (tag_value, parent_die, t) dw_die_ref parent_die; tree t; { - dw_die_ref die = (dw_die_ref) xcalloc (1, sizeof (die_node)); + dw_die_ref die = (dw_die_ref) ggc_alloc_cleared (sizeof (die_node)); die->die_tag = tag_value; @@ -5134,7 +5230,7 @@ new_die (tag_value, parent_die, t) { limbo_die_node *limbo_node; - limbo_node = (limbo_die_node *) xmalloc (sizeof (limbo_die_node)); + limbo_node = ggc_alloc_cleared (sizeof (limbo_die_node)); limbo_node->die = die; limbo_node->created_for = t; limbo_node->next = limbo_die_list; @@ -5191,9 +5287,8 @@ equate_decl_number_to_die (decl, decl_die) / DECL_DIE_TABLE_INCREMENT) * DECL_DIE_TABLE_INCREMENT; - decl_die_table - = (dw_die_ref *) xrealloc (decl_die_table, - sizeof (dw_die_ref) * num_allocated); + decl_die_table = ggc_realloc (decl_die_table, + sizeof (dw_die_ref) * num_allocated); memset ((char *) &decl_die_table[decl_die_table_allocated], 0, (num_allocated - decl_die_table_allocated) * sizeof (dw_die_ref)); @@ -5605,8 +5700,7 @@ same_dw_val_p (v1, v2, mark) case dw_val_class_flag: return v1->v.val_flag == v2->v.val_flag; case dw_val_class_str: - return !strcmp((const char *) HT_STR (&v1->v.val_str->id), - (const char *) HT_STR (&v2->v.val_str->id)); + return !strcmp(v1->v.val_str->str, v2->v.val_str->str); case dw_val_class_addr: r1 = v1->v.val_addr; @@ -6145,9 +6239,8 @@ build_abbrev_table (die) if (abbrev_die_table_in_use >= abbrev_die_table_allocated) { n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT; - abbrev_die_table - = (dw_die_ref *) xrealloc (abbrev_die_table, - sizeof (dw_die_ref) * n_alloc); + abbrev_die_table = ggc_realloc (abbrev_die_table, + sizeof (dw_die_ref) * n_alloc); memset ((char *) &abbrev_die_table[abbrev_die_table_allocated], 0, (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref)); @@ -6249,7 +6342,7 @@ size_of_die (die) if (AT_string_form (a) == DW_FORM_strp) size += DWARF_OFFSET_SIZE; else - size += HT_LEN (&a->dw_attr_val.v.val_str->id) + 1; + size += strlen (a->dw_attr_val.v.val_str->str) + 1; break; default: abort (); @@ -6529,8 +6622,7 @@ new_loc_list (expr, begin, end, section, gensym) const char *section; unsigned gensym; { - dw_loc_list_ref retlist - = (dw_loc_list_ref) xcalloc (1, sizeof (dw_loc_list_node)); + dw_loc_list_ref retlist = ggc_alloc_cleared (sizeof (dw_loc_list_node)); retlist->begin = begin; retlist->end = end; @@ -6884,9 +6976,11 @@ add_pubname (decl, die) { pubname_table_allocated += PUBNAME_TABLE_INCREMENT; pubname_table - = (pubname_ref) xrealloc (pubname_table, - (pubname_table_allocated - * sizeof (pubname_entry))); + = (pubname_ref) ggc_realloc (pubname_table, + (pubname_table_allocated + * sizeof (pubname_entry))); + memset (pubname_table + pubname_table_in_use, 0, + PUBNAME_TABLE_INCREMENT * sizeof (pubname_entry)); } p = &pubname_table[pubname_table_in_use++]; @@ -6942,8 +7036,11 @@ add_arange (decl, die) if (arange_table_in_use == arange_table_allocated) { arange_table_allocated += ARANGE_TABLE_INCREMENT; - arange_table = (dw_die_ref *) - xrealloc (arange_table, arange_table_allocated * sizeof (dw_die_ref)); + arange_table = ggc_realloc (arange_table, + (arange_table_allocated + * sizeof (dw_die_ref))); + memset (arange_table + arange_table_in_use, 0, + ARANGE_TABLE_INCREMENT * sizeof (dw_die_ref)); } arange_table[arange_table_in_use++] = die; @@ -7038,8 +7135,10 @@ add_ranges (block) { ranges_table_allocated += RANGES_TABLE_INCREMENT; ranges_table = (dw_ranges_ref) - xrealloc (ranges_table, (ranges_table_allocated - * sizeof (struct dw_ranges_struct))); + ggc_realloc (ranges_table, (ranges_table_allocated + * sizeof (struct dw_ranges_struct))); + memset (ranges_table + ranges_table_in_use, 0, + RANGES_TABLE_INCREMENT * sizeof (struct dw_ranges_struct)); } ranges_table[in_use].block_num = (block ? BLOCK_NUMBER (block) : 0); @@ -9090,7 +9189,7 @@ add_const_value_attribute (die, rtl) if (GET_MODE_CLASS (mode) == MODE_FLOAT) { unsigned length = GET_MODE_SIZE (mode) / 4; - long *array = (long *) xmalloc (sizeof (long) * length); + long *array = (long *) ggc_alloc (sizeof (long) * length); REAL_VALUE_TYPE rv; REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl); @@ -11974,15 +12073,6 @@ gen_decl_die (decl, context_die) abort (); } } - -static void -mark_limbo_die_list (ptr) - void *ptr ATTRIBUTE_UNUSED; -{ - limbo_die_node *node; - for (node = limbo_die_list; node; node = node->next) - ggc_mark_tree (node->created_for); -} /* Add Ada "use" clause information for SGI Workshop debugger. */ @@ -12225,6 +12315,8 @@ lookup_filename (file_name) file_table.allocated = i + FILE_TABLE_INCREMENT; file_table.table = (char **) xrealloc (file_table.table, file_table.allocated * sizeof (char *)); + memset (file_table.table + i, 0, + FILE_TABLE_INCREMENT * sizeof (char *)); } /* Add the new entry to the end of the filename table. */ @@ -12299,9 +12391,14 @@ dwarf2out_source_line (line, filename) separate_line_info_table_allocated += LINE_INFO_TABLE_INCREMENT; separate_line_info_table = (dw_separate_line_info_ref) - xrealloc (separate_line_info_table, - separate_line_info_table_allocated - * sizeof (dw_separate_line_info_entry)); + ggc_realloc (separate_line_info_table, + separate_line_info_table_allocated + * sizeof (dw_separate_line_info_entry)); + memset ((separate_line_info_table + + separate_line_info_table_in_use), + 0, + (LINE_INFO_TABLE_INCREMENT + * sizeof (dw_separate_line_info_entry))); } /* Add the new entry at the end of the line_info_table. */ @@ -12323,10 +12420,11 @@ dwarf2out_source_line (line, filename) { line_info_table_allocated += LINE_INFO_TABLE_INCREMENT; line_info_table - = (dw_line_info_ref) - xrealloc (line_info_table, - (line_info_table_allocated - * sizeof (dw_line_info_entry))); + = ggc_realloc (line_info_table, + (line_info_table_allocated + * sizeof (dw_line_info_entry))); + memset (line_info_table + line_info_table_in_use, 0, + LINE_INFO_TABLE_INCREMENT * sizeof (dw_line_info_entry)); } /* Add the new entry at the end of the line_info_table. */ @@ -12433,8 +12531,8 @@ dwarf2out_init (main_input_filename) lookup_filename (main_input_filename); /* Allocate the initial hunk of the decl_die_table. */ - decl_die_table - = (dw_die_ref *) xcalloc (DECL_DIE_TABLE_INCREMENT, sizeof (dw_die_ref)); + decl_die_table = ggc_alloc_cleared (DECL_DIE_TABLE_INCREMENT + * sizeof (dw_die_ref)); decl_die_table_allocated = DECL_DIE_TABLE_INCREMENT; decl_die_table_in_use = 0; @@ -12442,17 +12540,15 @@ dwarf2out_init (main_input_filename) VARRAY_TREE_INIT (decl_scope_table, 256, "decl_scope_table"); /* Allocate the initial hunk of the abbrev_die_table. */ - abbrev_die_table - = (dw_die_ref *) xcalloc (ABBREV_DIE_TABLE_INCREMENT, - sizeof (dw_die_ref)); + abbrev_die_table = ggc_alloc_cleared (ABBREV_DIE_TABLE_INCREMENT + * sizeof (dw_die_ref)); abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT; /* Zero-th entry is allocated, but unused */ abbrev_die_table_in_use = 1; /* Allocate the initial hunk of the line_info_table. */ - line_info_table - = (dw_line_info_ref) xcalloc (LINE_INFO_TABLE_INCREMENT, - sizeof (dw_line_info_entry)); + line_info_table = ggc_alloc_cleared (LINE_INFO_TABLE_INCREMENT + * sizeof (dw_line_info_entry)); line_info_table_allocated = LINE_INFO_TABLE_INCREMENT; /* Zero-th entry is allocated, but unused */ @@ -12470,8 +12566,6 @@ dwarf2out_init (main_input_filename) VARRAY_RTX_INIT (used_rtx_varray, 32, "used_rtx_varray"); - ggc_add_root (&limbo_die_list, 1, 1, mark_limbo_die_list); - ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0); ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label, DEBUG_ABBREV_SECTION_LABEL, 0); @@ -12508,39 +12602,21 @@ dwarf2out_init (main_input_filename) } } -/* Allocate a string in .debug_str hash table. */ - -static hashnode -indirect_string_alloc (tab) - hash_table *tab ATTRIBUTE_UNUSED; -{ - struct indirect_string_node *node; - - node = xmalloc (sizeof (struct indirect_string_node)); - node->refcount = 0; - node->form = 0; - node->label = NULL; - - return (hashnode) node; -} - /* A helper function for dwarf2out_finish called through ht_forall. Emit one queued .debug_str string. */ static int -output_indirect_string (pfile, h, v) - struct cpp_reader *pfile ATTRIBUTE_UNUSED; - hashnode h; - const PTR v ATTRIBUTE_UNUSED; +output_indirect_string (h, v) + void **h; + void *v ATTRIBUTE_UNUSED; { - struct indirect_string_node *node = (struct indirect_string_node *) h; + struct indirect_string_node *node = (struct indirect_string_node *) *h; if (node->form == DW_FORM_strp) { named_section_flags (DEBUG_STR_SECTION, DEBUG_STR_SECTION_FLAGS); ASM_OUTPUT_LABEL (asm_out_file, node->label); - assemble_string ((const char *) HT_STR (&node->id), - HT_LEN (&node->id) + 1); + assemble_string (node->str, strlen (node->str) + 1); } return 1; @@ -12607,8 +12683,6 @@ dwarf2out_finish (input_filename) else abort (); } - - free (node); } limbo_die_list = NULL; @@ -12724,7 +12798,7 @@ dwarf2out_finish (input_filename) /* If we emitted any DW_FORM_strp form attribute, output the string table too. */ if (debug_str_hash) - ht_forall (debug_str_hash, output_indirect_string, NULL); + htab_traverse (debug_str_hash, output_indirect_string, NULL); } #else diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 0099a50..eb1814a 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -5315,14 +5315,14 @@ init_emit_once (line_numbers) /* Initialize the CONST_INT, CONST_DOUBLE, and memory attribute hash tables. */ - const_int_htab = htab_create (37, const_int_htab_hash, - const_int_htab_eq, NULL); + const_int_htab = htab_create_ggc (37, const_int_htab_hash, + const_int_htab_eq, NULL); - const_double_htab = htab_create (37, const_double_htab_hash, - const_double_htab_eq, NULL); + const_double_htab = htab_create_ggc (37, const_double_htab_hash, + const_double_htab_eq, NULL); - mem_attrs_htab = htab_create (37, mem_attrs_htab_hash, - mem_attrs_htab_eq, NULL); + mem_attrs_htab = htab_create_ggc (37, mem_attrs_htab_hash, + mem_attrs_htab_eq, NULL); no_line_numbers = ! line_numbers; diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 0c53604..3847fc0 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -1395,7 +1395,7 @@ size_int_type_wide (number, type) if (size_htab == 0) { - size_htab = htab_create (1024, size_htab_hash, size_htab_eq, NULL); + size_htab = htab_create_ggc (1024, size_htab_hash, size_htab_eq, NULL); new_const = make_node (INTEGER_CST); } diff --git a/gcc/function.c b/gcc/function.c index 0a0f56d..1c972d2 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -125,7 +125,7 @@ int current_function_uses_only_leaf_regs; int virtuals_instantiated; /* Assign unique numbers to labels generated for profiling, debugging, etc. */ -static int funcdef_no; +static GTY(()) int funcdef_no; /* These variables hold pointers to functions to create and destroy target specific, per-function data structures. */ diff --git a/gcc/gcc.c b/gcc/gcc.c index 618d272..8b27a0ac 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -421,6 +421,7 @@ or with constant text in a single argument. %w marks the argument containing or following the %w as the "output file" of this compilation. This puts the argument into the sequence of arguments that %o will substitute later. + %V indicates that this compilation produces no "output file". %W{...} like %{...} but mark last argument supplied within as a file to be deleted on failure. @@ -914,9 +915,19 @@ static const struct compiler default_compilers[] = %(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)", 0}, {".h", "@c-header", 0}, {"@c-header", - "%{!E:%ecompilation of header file requested} \ - %(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)", - 0}, + /* cc1 has an integrated ISO C preprocessor. We should invoke the + external preprocessor if -save-temps is given. */ + "%{E|M|MM:%(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)}\ + %{!E:%{!M:%{!MM:\ + %{save-temps|traditional-cpp:%(trad_capable_cpp) \ + %(cpp_options) %b.i \n\ + cc1 -fpreprocessed %b.i %(cc1_options)\ + -o %g.s %{!o*:--output-pch=%i.pch}\ + %W{o*:--output-pch=%*}%V}\ + %{!save-temps:%{!traditional-cpp:\ + cc1 %(cpp_unique_options) %(cc1_options)\ + -o %g.s %{!o*:--output-pch=%i.pch}\ + %W{o*:--output-pch=%*}%V}}}}}", 0}, {".i", "@cpp-output", 0}, {"@cpp-output", "%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}", 0}, @@ -4765,6 +4776,10 @@ do_spec_1 (spec, inswitch, soft_matched_part) this_is_library_file = 1; break; + case 'V': + outfiles[input_file_number] = NULL; + break; + case 'w': this_is_output_file = 1; break; @@ -6079,6 +6094,7 @@ main (argc, argv) size_t i; int value; int linker_was_run = 0; + int num_linker_inputs = 0; char *explicit_link_files; char *specs_file; const char *p; @@ -6516,9 +6532,15 @@ main (argc, argv) error_count++; } + /* Determine if there are any linker input files. */ + num_linker_inputs = 0; + for (i = 0; (int) i < n_infiles; i++) + if (explicit_link_files[i] || outfiles[i] != NULL) + num_linker_inputs++; + /* Run ld to link all the compiler output files. */ - if (error_count == 0) + if (num_linker_inputs > 0 && error_count == 0) { int tmp = execution_count; diff --git a/gcc/gengtype.c b/gcc/gengtype.c index 855e5ed..b279263 100644 --- a/gcc/gengtype.c +++ b/gcc/gengtype.c @@ -603,14 +603,6 @@ adjust_field_rtx_def (t, opt) subfields->opt->name = "skip"; subfields->opt->info = NULL; } - else if ((size_t) rtx_next[i] == aindex) - { - /* The 'next' field will be marked by the chain_next option. */ - subfields->opt = xmalloc (sizeof (*subfields->opt)); - subfields->opt->next = nodot; - subfields->opt->name = "skip"; - subfields->opt->info = NULL; - } else subfields->opt = nodot; } @@ -1364,70 +1356,78 @@ struct flist { outf_p f; }; -static void output_escaped_param PARAMS ((outf_p , const char *, const char *, - const char *, const char *, - struct fileloc *)); +struct walk_type_data; + +/* For scalars and strings, given the item in 'val'. + For structures, given a pointer to the item in 'val'. + For misc. pointers, given the item in 'val'. +*/ +typedef void (*process_field_fn) + PARAMS ((type_p f, const struct walk_type_data *p)); +typedef void (*func_name_fn) + PARAMS ((type_p s, const struct walk_type_data *p)); + +/* Parameters for write_types. */ + +struct write_types_data +{ + const char *prefix; + const char *param_prefix; + const char *subfield_marker_routine; + const char *marker_routine; + const char *reorder_note_routine; + const char *comment; +}; + +static void output_escaped_param PARAMS ((struct walk_type_data *d, + const char *, const char *)); static void output_mangled_typename PARAMS ((outf_p, type_p)); -static void write_gc_structure_fields - PARAMS ((outf_p , type_p, const char *, const char *, options_p, - int, struct fileloc *, lang_bitmap, type_p *)); -static void write_gc_marker_routine_for_structure PARAMS ((type_p, type_p, - type_p *)); -static void write_gc_types PARAMS ((type_p structures, type_p param_structs)); +static void walk_type PARAMS ((type_p t, struct walk_type_data *d)); +static void write_func_for_structure + PARAMS ((type_p orig_s, type_p s, type_p * param, + const struct write_types_data *wtd)); +static void write_types_process_field + PARAMS ((type_p f, const struct walk_type_data *d)); +static void write_types PARAMS ((type_p structures, + type_p param_structs, + const struct write_types_data *wtd)); +static void write_types_local_process_field + PARAMS ((type_p f, const struct walk_type_data *d)); +static void write_local_func_for_structure + PARAMS ((type_p orig_s, type_p s, type_p * param)); +static void write_local PARAMS ((type_p structures, + type_p param_structs)); static void write_enum_defn PARAMS ((type_p structures, type_p param_structs)); +static int contains_scalar_p PARAMS ((type_p t)); static void put_mangled_filename PARAMS ((outf_p , const char *)); static void finish_root_table PARAMS ((struct flist *flp, const char *pfx, const char *tname, const char *lastname, const char *name)); -static void write_gc_root PARAMS ((outf_p , pair_p, type_p, const char *, int, +static void write_root PARAMS ((outf_p , pair_p, type_p, const char *, int, struct fileloc *, const char *)); -static void write_gc_roots PARAMS ((pair_p)); +static void write_array PARAMS ((outf_p f, pair_p v, + const struct write_types_data *wtd)); +static void write_roots PARAMS ((pair_p)); -static int gc_counter; +/* Parameters for walk_type. */ -/* Print PARAM to OF processing escapes. VAL references the current object, - PREV_VAL the object containing the current object, ONAME is the name - of the option and LINE is used to print error messages. */ - -static void -output_escaped_param (of, param, val, prev_val, oname, line) - outf_p of; - const char *param; - const char *val; - const char *prev_val; - const char *oname; - struct fileloc *line; +struct walk_type_data { - const char *p; - - for (p = param; *p; p++) - if (*p != '%') - oprintf (of, "%c", *p); - else switch (*++p) - { - case 'h': - oprintf (of, "(%s)", val); - break; - case '0': - oprintf (of, "(*x)"); - break; - case '1': - oprintf (of, "(%s)", prev_val); - break; - case 'a': - { - const char *pp = val + strlen (val); - while (pp[-1] == ']') - while (*pp != '[') - pp--; - oprintf (of, "%s", pp); - } - break; - default: - error_at_line (line, "`%s' option contains bad escape %c%c", - oname, '%', *p); - } -} + process_field_fn process_field; + const void *cookie; + outf_p of; + options_p opt; + const char *val; + const char *prev_val[4]; + int indent; + int counter; + struct fileloc *line; + lang_bitmap bitmap; + type_p *param; + int used_length; + type_p orig_s; + const char *reorder_fn; +}; /* Print a mangled name representing T to OF. */ @@ -1469,423 +1469,491 @@ output_mangled_typename (of, t) } } -/* Write out code to OF which marks the fields of S. VAL references - the current object, PREV_VAL the object containing the current - object, OPTS is a list of options to apply, INDENT is the current - indentation level, LINE is used to print error messages, BITMAP - indicates which languages to print the structure for, and PARAM is - the current parameter (from an enclosing param_is option). */ +/* Print PARAM to D->OF processing escapes. D->VAL references the + current object, D->PREV_VAL the object containing the current + object, ONAME is the name of the option and D->LINE is used to + print error messages. */ static void -write_gc_structure_fields (of, s, val, prev_val, opts, indent, line, bitmap, - param) - outf_p of; - type_p s; - const char *val; - const char *prev_val; - options_p opts; - int indent; - struct fileloc *line; - lang_bitmap bitmap; - type_p * param; +output_escaped_param (d, param, oname) + struct walk_type_data *d; + const char *param; + const char *oname; { - pair_p f; - int seen_default = 0; - - if (! s->u.s.line.file) - error_at_line (line, "incomplete structure `%s'", s->u.s.tag); - else if ((s->u.s.bitmap & bitmap) != bitmap) - { - error_at_line (line, "structure defined for mismatching languages"); - error_at_line (&s->u.s.line, "one structure defined here"); - } + const char *p; - if (s->kind == TYPE_UNION) - { - const char *tagexpr = NULL; - options_p oo; - - for (oo = opts; oo; oo = oo->next) - if (strcmp (oo->name, "desc") == 0) - tagexpr = (const char *)oo->info; - if (tagexpr == NULL) + for (p = param; *p; p++) + if (*p != '%') + oprintf (d->of, "%c", *p); + else switch (*++p) + { + case 'h': + oprintf (d->of, "(%s)", d->prev_val[2]); + break; + case '0': + oprintf (d->of, "(%s)", d->prev_val[0]); + break; + case '1': + oprintf (d->of, "(%s)", d->prev_val[1]); + break; + case 'a': { - tagexpr = "1"; - error_at_line (line, "missing `desc' option"); + const char *pp = d->val + strlen (d->val); + while (pp[-1] == ']') + while (*pp != '[') + pp--; + oprintf (d->of, "%s", pp); } + break; + default: + error_at_line (d->line, "`%s' option contains bad escape %c%c", + oname, '%', *p); + } +} - oprintf (of, "%*sswitch (", indent, ""); - output_escaped_param (of, tagexpr, val, prev_val, "desc", line); - oprintf (of, ")\n"); - indent += 2; - oprintf (of, "%*s{\n", indent, ""); - } - - for (f = s->u.s.fields; f; f = f->next) - { - const char *tagid = NULL; - const char *length = NULL; - int skip_p = 0; - int default_p = 0; - int maybe_undef_p = 0; - int use_param_num = -1; - int use_params_p = 0; - int needs_cast_p = 0; - options_p oo; - type_p t = f->type; - const char *dot = "."; - - for (oo = f->opt; oo; oo = oo->next) - if (strcmp (oo->name, "length") == 0) - length = (const char *)oo->info; - else if (strcmp (oo->name, "maybe_undef") == 0) - maybe_undef_p = 1; - else if (strcmp (oo->name, "tag") == 0) - tagid = (const char *)oo->info; - else if (strcmp (oo->name, "special") == 0) - ; - else if (strcmp (oo->name, "skip") == 0) - skip_p = 1; - else if (strcmp (oo->name, "default") == 0) - default_p = 1; - else if (strcmp (oo->name, "desc") == 0) - ; - else if (strcmp (oo->name, "descbits") == 0) - ; - else if (strcmp (oo->name, "param_is") == 0) - ; - else if (strncmp (oo->name, "use_param", 9) == 0 - && (oo->name[9] == '\0' || ISDIGIT (oo->name[9]))) - use_param_num = oo->name[9] == '\0' ? 0 : oo->name[9] - '0'; - else if (strcmp (oo->name, "use_params") == 0) - use_params_p = 1; - else if (strcmp (oo->name, "dot") == 0) - dot = (const char *)oo->info; - else - error_at_line (&f->line, "unknown field option `%s'\n", oo->name); +/* 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 + cases. D->PREV_VAL lists the objects containing the current object, + D->OPT is a list of options to apply, D->INDENT is the current + indentation level, D->LINE is used to print error messages, + D->BITMAP indicates which languages to print the structure for, and + D->PARAM is the current parameter (from an enclosing param_is + option). */ - if (skip_p) - continue; +static void +walk_type (t, d) + type_p t; + struct walk_type_data *d; +{ + const char *length = NULL; + const char *desc = NULL; + int maybe_undef_p = 0; + int use_param_num = -1; + int use_params_p = 0; + int needs_cast_p = 0; + options_p oo; + + for (oo = d->opt; oo; oo = oo->next) + if (strcmp (oo->name, "length") == 0) + length = (const char *)oo->info; + else if (strcmp (oo->name, "maybe_undef") == 0) + maybe_undef_p = 1; + else if (strncmp (oo->name, "use_param", 9) == 0 + && (oo->name[9] == '\0' || ISDIGIT (oo->name[9]))) + use_param_num = oo->name[9] == '\0' ? 0 : oo->name[9] - '0'; + else if (strcmp (oo->name, "use_params") == 0) + use_params_p = 1; + else if (strcmp (oo->name, "desc") == 0) + desc = (const char *)oo->info; + else if (strcmp (oo->name, "dot") == 0) + ; + else if (strcmp (oo->name, "tag") == 0) + ; + else if (strcmp (oo->name, "special") == 0) + ; + else if (strcmp (oo->name, "skip") == 0) + ; + else if (strcmp (oo->name, "default") == 0) + ; + else if (strcmp (oo->name, "descbits") == 0) + ; + else if (strcmp (oo->name, "param_is") == 0) + ; + else if (strcmp (oo->name, "chain_next") == 0) + ; + else if (strcmp (oo->name, "chain_prev") == 0) + ; + else if (strcmp (oo->name, "reorder") == 0) + ; + else + error_at_line (d->line, "unknown option `%s'\n", oo->name); - if (use_params_p) - { - int pointer_p = t->kind == TYPE_POINTER; + if (d->used_length) + length = NULL; - if (pointer_p) - t = t->u.p; - t = find_param_structure (t, param); - if (pointer_p) - t = create_pointer (t); - } + if (use_params_p) + { + int pointer_p = t->kind == TYPE_POINTER; - if (use_param_num != -1) - { - if (param != NULL && param[use_param_num] != NULL) - { - type_p nt = param[use_param_num]; - - if (t->kind == TYPE_ARRAY) - nt = create_array (nt, t->u.a.len); - else if (length != NULL && t->kind == TYPE_POINTER) - nt = create_pointer (nt); - needs_cast_p = (t->kind != TYPE_POINTER - && nt->kind == TYPE_POINTER); - t = nt; - } - else if (s->kind != TYPE_UNION) - error_at_line (&f->line, "no parameter defined"); - } - - if (t->kind == TYPE_SCALAR - || (t->kind == TYPE_ARRAY - && t->u.a.p->kind == TYPE_SCALAR)) - continue; + if (pointer_p) + t = t->u.p; + 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); + if (pointer_p) + t = create_pointer (t); + } - seen_default |= default_p; - - if (maybe_undef_p - && (t->kind != TYPE_POINTER - || t->u.p->kind != TYPE_STRUCT)) - error_at_line (&f->line, - "field `%s' has invalid option `maybe_undef_p'\n", - f->name); - if (s->kind == TYPE_UNION) + if (use_param_num != -1) + { + if (d->param != NULL && d->param[use_param_num] != NULL) { - if (tagid) - { - oprintf (of, "%*scase %s:\n", indent, "", tagid); - - } - else if (default_p) - { - oprintf (of, "%*sdefault:\n", indent, ""); - } - else - { - error_at_line (&f->line, "field `%s' has no tag", f->name); - continue; - } - indent += 2; + type_p nt = d->param[use_param_num]; + + if (t->kind == TYPE_ARRAY) + nt = create_array (nt, t->u.a.len); + else if (length != NULL && t->kind == TYPE_POINTER) + nt = create_pointer (nt); + needs_cast_p = (t->kind != TYPE_POINTER + && nt->kind == TYPE_POINTER); + t = nt; } + else + error_at_line (d->line, "no parameter defined for `%s'", + d->val); + } + + if (maybe_undef_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", + d->val); + return; + } + + switch (t->kind) + { + case TYPE_SCALAR: + case TYPE_STRING: + d->process_field (t, d); + break; - switch (t->kind) - { - case TYPE_STRING: - /* Do nothing; strings go in the string pool. */ - break; + case TYPE_POINTER: + { + if (maybe_undef_p + && t->u.p->u.s.line.file == NULL) + { + oprintf (d->of, "%*sif (%s) abort();\n", d->indent, "", d->val); + break; + } - case TYPE_LANG_STRUCT: + if (! length) { - type_p ti; - for (ti = t->u.s.lang_struct; ti; ti = ti->next) - if (ti->u.s.bitmap & bitmap) - { - t = ti; - break; - } - if (ti == NULL) + if (! UNION_OR_STRUCT_P (t->u.p) + && t->u.p->kind != TYPE_PARAM_STRUCT) { - error_at_line (&f->line, - "structure not defined for this language"); + error_at_line (d->line, + "field `%s' is pointer to unimplemented type", + d->val); break; } + + d->process_field (t->u.p, d); } - /* Fall through... */ - case TYPE_STRUCT: - case TYPE_UNION: + else { + int loopcounter = d->counter++; + const char *oldval = d->val; + const char *oldprevval3 = d->prev_val[3]; char *newval; - newval = xasprintf ("%s%s%s", val, dot, f->name); - write_gc_structure_fields (of, t, newval, val, f->opt, indent, - &f->line, bitmap, param); + oprintf (d->of, "%*sif (%s != NULL) {\n", d->indent, "", d->val); + d->indent += 2; + oprintf (d->of, "%*ssize_t i%d;\n", d->indent, "", loopcounter); + d->process_field(t, d); + oprintf (d->of, "%*sfor (i%d = 0; i%d < (size_t)(", d->indent, "", + loopcounter, loopcounter); + output_escaped_param (d, length, "length"); + oprintf (d->of, "); i%d++) {\n", loopcounter); + d->indent += 2; + d->val = newval = xasprintf ("%s[i%d]", oldval, loopcounter); + d->used_length = 1; + d->prev_val[3] = oldval; + walk_type (t->u.p, d); free (newval); - break; + d->val = oldval; + d->prev_val[3] = oldprevval3; + d->used_length = 0; + d->indent -= 2; + oprintf (d->of, "%*s}\n", d->indent, ""); + d->indent -= 2; + oprintf (d->of, "%*s}\n", d->indent, ""); } + } + break; - case TYPE_POINTER: - if (! length) - { - if (maybe_undef_p - && t->u.p->u.s.line.file == NULL) - oprintf (of, "%*sif (%s%s%s) abort();\n", indent, "", - val, dot, f->name); - else if (UNION_OR_STRUCT_P (t->u.p) - || t->u.p->kind == TYPE_PARAM_STRUCT) - { - oprintf (of, "%*sgt_ggc_m_", indent, ""); - output_mangled_typename (of, t->u.p); - oprintf (of, " ("); - if (needs_cast_p) - oprintf (of, "(%s %s *)", - UNION_P (t->u.p) ? "union" : "struct", - t->u.p->u.s.tag); - oprintf (of, "%s%s%s);\n", val, dot, f->name); - } - else - error_at_line (&f->line, "field `%s' is pointer to scalar", - f->name); - break; - } - else if (t->u.p->kind == TYPE_SCALAR - || t->u.p->kind == TYPE_STRING) - oprintf (of, "%*sggc_mark (%s%s%s);\n", indent, "", - val, dot, f->name); - else - { - int loopcounter = ++gc_counter; - - oprintf (of, "%*sif (%s%s%s != NULL) {\n", indent, "", - val, dot, f->name); - indent += 2; - oprintf (of, "%*ssize_t i%d;\n", indent, "", loopcounter); - oprintf (of, "%*sggc_set_mark (%s%s%s);\n", indent, "", - val, dot, f->name); - oprintf (of, "%*sfor (i%d = 0; i%d < (size_t)(", indent, "", - loopcounter, loopcounter); - output_escaped_param (of, length, val, prev_val, "length", line); - oprintf (of, "); i%d++) {\n", loopcounter); - indent += 2; - switch (t->u.p->kind) - { - case TYPE_STRUCT: - case TYPE_UNION: - { - char *newval; - - newval = xasprintf ("%s%s%s[i%d]", val, dot, f->name, - loopcounter); - write_gc_structure_fields (of, t->u.p, newval, val, - f->opt, indent, &f->line, - bitmap, param); - free (newval); - break; - } - case TYPE_POINTER: - if (UNION_OR_STRUCT_P (t->u.p->u.p) - || t->u.p->u.p->kind == TYPE_PARAM_STRUCT) - { - oprintf (of, "%*sgt_ggc_m_", indent, ""); - output_mangled_typename (of, t->u.p->u.p); - oprintf (of, " (%s%s%s[i%d]);\n", val, dot, f->name, - loopcounter); - } - else - error_at_line (&f->line, - "field `%s' is array of pointer to scalar", - f->name); - break; - default: - error_at_line (&f->line, - "field `%s' is array of unimplemented type", - f->name); - break; - } - indent -= 2; - oprintf (of, "%*s}\n", indent, ""); - indent -= 2; - oprintf (of, "%*s}\n", indent, ""); - } + case TYPE_ARRAY: + { + int loopcounter = d->counter++; + const char *oldval = d->val; + char *newval; + + /* If it's an array of scalars, we optimise by not generating + any code. */ + if (t->u.a.p->kind == TYPE_SCALAR) break; + + oprintf (d->of, "%*s{\n", d->indent, ""); + d->indent += 2; + oprintf (d->of, "%*ssize_t i%d;\n", d->indent, "", loopcounter); + oprintf (d->of, "%*sfor (i%d = 0; i%d < (size_t)(", d->indent, "", + loopcounter, loopcounter); + if (length) + output_escaped_param (d, length, "length"); + else + oprintf (d->of, "%s", t->u.a.len); + oprintf (d->of, "); i%d++) {\n", loopcounter); + d->indent += 2; + d->val = newval = xasprintf ("%s[i%d]", oldval, loopcounter); + d->used_length = 1; + walk_type (t->u.a.p, d); + free (newval); + d->used_length = 0; + d->val = oldval; + d->indent -= 2; + oprintf (d->of, "%*s}\n", d->indent, ""); + d->indent -= 2; + oprintf (d->of, "%*s}\n", d->indent, ""); + } + break; + + case TYPE_STRUCT: + case TYPE_UNION: + { + pair_p f; + const char *oldval = d->val; + const char *oldprevval1 = d->prev_val[1]; + const char *oldprevval2 = d->prev_val[2]; + const int union_p = t->kind == TYPE_UNION; + int seen_default_p = 0; + options_p o; + + if (! t->u.s.line.file) + error_at_line (d->line, "incomplete structure `%s'", t->u.s.tag); - case TYPE_ARRAY: + if ((d->bitmap & t->u.s.bitmap) != d->bitmap) { - int loopcounter = ++gc_counter; - type_p ta; - int i; - - if (! length && - (strcmp (t->u.a.len, "0") == 0 - || strcmp (t->u.a.len, "1") == 0)) - error_at_line (&f->line, - "field `%s' is array of size %s", - f->name, t->u.a.len); - - /* Arrays of scalars can be ignored. */ - for (ta = t; ta->kind == TYPE_ARRAY; ta = ta->u.a.p) - ; - if (ta->kind == TYPE_SCALAR - || ta->kind == TYPE_STRING) - break; + error_at_line (d->line, + "structure `%s' defined for mismatching languages", + t->u.s.tag); + error_at_line (&t->u.s.line, "one structure defined here"); + } - oprintf (of, "%*s{\n", indent, ""); - indent += 2; + /* Some things may also be defined in the structure's options. */ + for (o = t->u.s.opt; o; o = o->next) + if (! desc && strcmp (o->name, "desc") == 0) + desc = (const char *)o->info; - for (ta = t, i = 0; ta->kind == TYPE_ARRAY; ta = ta->u.a.p, i++) + d->prev_val[2] = oldval; + d->prev_val[1] = oldprevval2; + if (union_p) + { + if (desc == NULL) { - oprintf (of, "%*ssize_t i%d_%d;\n", - indent, "", loopcounter, i); - oprintf (of, "%*sconst size_t ilimit%d_%d = (", - indent, "", loopcounter, i); - if (i == 0 && length != NULL) - output_escaped_param (of, length, val, prev_val, - "length", line); - else - oprintf (of, "%s", ta->u.a.len); - oprintf (of, ");\n"); + error_at_line (d->line, "missing `desc' option for union `%s'", + t->u.s.tag); + desc = "1"; } - - for (ta = t, i = 0; ta->kind == TYPE_ARRAY; ta = ta->u.a.p, i++) + oprintf (d->of, "%*sswitch (", d->indent, ""); + output_escaped_param (d, desc, "desc"); + oprintf (d->of, ")\n"); + d->indent += 2; + oprintf (d->of, "%*s{\n", d->indent, ""); + } + for (f = t->u.s.fields; f; f = f->next) + { + options_p oo; + const char *dot = "."; + const char *tagid = NULL; + int skip_p = 0; + int default_p = 0; + int use_param_p = 0; + char *newval; + + d->reorder_fn = NULL; + for (oo = f->opt; oo; oo = oo->next) + if (strcmp (oo->name, "dot") == 0) + dot = (const char *)oo->info; + else if (strcmp (oo->name, "tag") == 0) + tagid = (const char *)oo->info; + else if (strcmp (oo->name, "skip") == 0) + skip_p = 1; + else if (strcmp (oo->name, "default") == 0) + default_p = 1; + else if (strcmp (oo->name, "reorder") == 0) + d->reorder_fn = (const char *)oo->info; + else if (strncmp (oo->name, "use_param", 9) == 0 + && (oo->name[9] == '\0' || ISDIGIT (oo->name[9]))) + use_param_p = 1; + + if (skip_p) + continue; + + if (union_p && tagid) { - oprintf (of, - "%*sfor (i%d_%d = 0; i%d_%d < ilimit%d_%d; i%d_%d++) {\n", - indent, "", loopcounter, i, loopcounter, i, - loopcounter, i, loopcounter, i); - indent += 2; + oprintf (d->of, "%*scase %s:\n", d->indent, "", tagid); + d->indent += 2; } - - if (ta->kind == TYPE_POINTER - && (UNION_OR_STRUCT_P (ta->u.p) - || ta->u.p->kind == TYPE_PARAM_STRUCT)) + else if (union_p && default_p) { - oprintf (of, "%*sgt_ggc_m_", indent, ""); - output_mangled_typename (of, ta->u.p); - oprintf (of, " (%s%s%s", val, dot, f->name); - for (ta = t, i = 0; - ta->kind == TYPE_ARRAY; - ta = ta->u.a.p, i++) - oprintf (of, "[i%d_%d]", loopcounter, i); - oprintf (of, ");\n"); + oprintf (d->of, "%*sdefault:\n", d->indent, ""); + d->indent += 2; + seen_default_p = 1; } - else if (ta->kind == TYPE_STRUCT || ta->kind == TYPE_UNION) + else if (! union_p && (default_p || tagid)) + error_at_line (d->line, + "can't use `%s' outside a union on field `%s'", + default_p ? "default" : "tag", f->name); + else if (union_p && ! (default_p || tagid) + && f->type->kind == TYPE_SCALAR) { - char *newval; - int len; - - len = strlen (val) + strlen (f->name) + 2; - for (ta = t; ta->kind == TYPE_ARRAY; ta = ta->u.a.p) - len += sizeof ("[i_]") + 2*6; - - newval = xmalloc (len); - sprintf (newval, "%s%s%s", val, dot, f->name); - for (ta = t, i = 0; - ta->kind == TYPE_ARRAY; - ta = ta->u.a.p, i++) - sprintf (newval + strlen (newval), "[i%d_%d]", - loopcounter, i); - write_gc_structure_fields (of, t->u.p, newval, val, - f->opt, indent, &f->line, bitmap, - param); - free (newval); + fprintf (stderr, + "%s:%d: warning: field `%s' is missing `tag' or `default' option\n", + d->line->file, d->line->line, f->name); + continue; } - else if (ta->kind == TYPE_POINTER && ta->u.p->kind == TYPE_SCALAR - && use_param_num != -1 && param == NULL) - oprintf (of, "%*sabort();\n", indent, ""); - else - error_at_line (&f->line, - "field `%s' is array of unimplemented type", + else if (union_p && ! (default_p || tagid)) + error_at_line (d->line, + "field `%s' is missing `tag' or `default' option", f->name); - for (ta = t, i = 0; ta->kind == TYPE_ARRAY; ta = ta->u.a.p, i++) + + d->line = &f->line; + d->val = newval = xasprintf ("%s%s%s", oldval, dot, f->name); + d->opt = f->opt; + + if (union_p && use_param_p && d->param == NULL) + oprintf (d->of, "%*sabort();\n", d->indent, ""); + else + walk_type (f->type, d); + + free (newval); + + if (union_p) { - indent -= 2; - oprintf (of, "%*s}\n", indent, ""); + oprintf (d->of, "%*sbreak;\n", d->indent, ""); + d->indent -= 2; } + } + d->reorder_fn = NULL; - indent -= 2; - oprintf (of, "%*s}\n", indent, ""); - break; + d->val = oldval; + d->prev_val[1] = oldprevval1; + d->prev_val[2] = oldprevval2; + + if (union_p && ! seen_default_p) + { + oprintf (d->of, "%*sdefault:\n", d->indent, ""); + oprintf (d->of, "%*s break;\n", d->indent, ""); + } + if (union_p) + { + oprintf (d->of, "%*s}\n", d->indent, ""); + d->indent -= 2; } + } + break; - default: - error_at_line (&f->line, - "field `%s' is unimplemented type", - f->name); - break; - } + case TYPE_LANG_STRUCT: + { + type_p nt; + for (nt = t->u.s.lang_struct; nt; nt = nt->next) + if ((d->bitmap & nt->u.s.bitmap) == d->bitmap) + break; + if (nt == NULL) + error_at_line (d->line, "structure `%s' differs between languages", + t->u.s.tag); + else + walk_type (nt, d); + } + break; + + case TYPE_PARAM_STRUCT: + { + type_p *oldparam = d->param; + + d->param = t->u.param_struct.param; + walk_type (t->u.param_struct.stru, d); + d->param = oldparam; + } + break; - if (s->kind == TYPE_UNION) - { - oprintf (of, "%*sbreak;\n", indent, ""); - indent -= 2; - } + default: + abort (); } - if (s->kind == TYPE_UNION) +} + +/* process_field routine for marking routines. */ + +static void +write_types_process_field (f, d) + type_p f; + const struct walk_type_data *d; +{ + const struct write_types_data *wtd; + wtd = (const struct write_types_data *) d->cookie; + + switch (f->kind) { - if (! seen_default) + case TYPE_POINTER: + oprintf (d->of, "%*s%s (%s", d->indent, "", + wtd->subfield_marker_routine, d->val); + if (wtd->param_prefix) { - oprintf (of, "%*sdefault:\n", indent, ""); - oprintf (of, "%*s break;\n", indent, ""); + oprintf (d->of, ", %s", d->prev_val[3]); + if (d->orig_s) + { + oprintf (d->of, ", gt_%s_", wtd->param_prefix); + output_mangled_typename (d->of, d->orig_s); + } + else + oprintf (d->of, ", gt_%sa_%s", wtd->param_prefix, d->prev_val[0]); } - oprintf (of, "%*s}\n", indent, ""); - indent -= 2; + oprintf (d->of, ");\n"); + if (d->reorder_fn && wtd->reorder_note_routine) + oprintf (d->of, "%*s%s (%s, %s, %s);\n", d->indent, "", + wtd->reorder_note_routine, d->val, + d->prev_val[3], d->reorder_fn); + break; + + case TYPE_STRING: + if (wtd->param_prefix == NULL) + break; + + case TYPE_STRUCT: + case TYPE_UNION: + case TYPE_LANG_STRUCT: + case TYPE_PARAM_STRUCT: + oprintf (d->of, "%*sgt_%s_", d->indent, "", wtd->prefix); + output_mangled_typename (d->of, f); + oprintf (d->of, " (%s);\n", d->val); + if (d->reorder_fn && wtd->reorder_note_routine) + oprintf (d->of, "%*s%s (%s, %s, %s);\n", d->indent, "", + wtd->reorder_note_routine, d->val, d->val, + d->reorder_fn); + break; + + case TYPE_SCALAR: + break; + + default: + abort (); } } -/* Write out a marker routine for S. PARAM is the parameter from an - enclosing PARAM_IS option. */ +/* For S, a structure that's part of ORIG_S, and using parameters + PARAM, write out a routine that: + - Takes a parameter, a void * but actually of type *S + - If SEEN_ROUTINE returns nonzero, calls write_types_process_field on each + field of S or its substructures and (in some cases) things + that are pointed to by S. +*/ static void -write_gc_marker_routine_for_structure (orig_s, s, param) +write_func_for_structure (orig_s, s, param, wtd) type_p orig_s; type_p s; type_p * param; + const struct write_types_data *wtd; { - outf_p f; const char *fn = s->u.s.line.file; int i; const char *chain_next = NULL; const char *chain_prev = NULL; options_p opt; + struct walk_type_data d; /* This is a hack, and not the good kind either. */ for (i = NUM_PARAM - 1; i >= 0; i--) @@ -1893,7 +1961,8 @@ write_gc_marker_routine_for_structure (orig_s, s, param) && UNION_OR_STRUCT_P (param[i]->u.p)) fn = param[i]->u.p->u.s.line.file; - f = get_output_file_with_visibility (fn); + memset (&d, 0, sizeof (d)); + d.of = get_output_file_with_visibility (fn); for (opt = s->u.s.opt; opt; opt = opt->next) if (strcmp (opt->name, "chain_next") == 0) @@ -1904,80 +1973,113 @@ write_gc_marker_routine_for_structure (orig_s, s, param) if (chain_prev != NULL && chain_next == NULL) error_at_line (&s->u.s.line, "chain_prev without chain_next"); - oprintf (f, "\n"); - oprintf (f, "void\n"); + d.process_field = write_types_process_field; + d.cookie = wtd; + d.orig_s = orig_s; + d.opt = s->u.s.opt; + d.line = &s->u.s.line; + d.bitmap = s->u.s.bitmap; + d.param = param; + d.prev_val[0] = "*x"; + d.prev_val[1] = "not valid postage"; /* guarantee an error */ + d.prev_val[3] = "x"; + d.val = "(*x)"; + + oprintf (d.of, "\n"); + oprintf (d.of, "void\n"); if (param == NULL) - oprintf (f, "gt_ggc_mx_%s", s->u.s.tag); + oprintf (d.of, "gt_%sx_%s", wtd->prefix, orig_s->u.s.tag); else { - oprintf (f, "gt_ggc_m_"); - output_mangled_typename (f, orig_s); + oprintf (d.of, "gt_%s_", wtd->prefix); + output_mangled_typename (d.of, orig_s); } - oprintf (f, " (x_p)\n"); - oprintf (f, " void *x_p;\n"); - oprintf (f, "{\n"); - oprintf (f, " %s %s * %sx = (%s %s *)x_p;\n", + oprintf (d.of, " (x_p)\n"); + oprintf (d.of, " void *x_p;\n"); + oprintf (d.of, "{\n"); + oprintf (d.of, " %s %s * %sx = (%s %s *)x_p;\n", s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag, chain_next == NULL ? "const " : "", s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag); if (chain_next != NULL) - oprintf (f, " %s %s * xlimit = x;\n", + oprintf (d.of, " %s %s * xlimit = x;\n", s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag); if (chain_next == NULL) - oprintf (f, " if (ggc_test_and_set_mark (x))\n"); + { + oprintf (d.of, " if (%s (x", wtd->marker_routine); + if (wtd->param_prefix) + { + oprintf (d.of, ", x, gt_%s_", wtd->param_prefix); + output_mangled_typename (d.of, orig_s); + } + oprintf (d.of, "))\n"); + } else { - oprintf (f, " while (ggc_test_and_set_mark (xlimit))\n"); - oprintf (f, " xlimit = ("); - output_escaped_param (f, chain_next, "*xlimit", "*xlimit", - "chain_next", &s->u.s.line); - oprintf (f, ");\n"); + oprintf (d.of, " while (%s (xlimit", wtd->marker_routine); + if (wtd->param_prefix) + { + oprintf (d.of, ", xlimit, gt_%s_", wtd->param_prefix); + output_mangled_typename (d.of, orig_s); + } + oprintf (d.of, "))\n"); + oprintf (d.of, " xlimit = ("); + d.prev_val[2] = "*xlimit"; + output_escaped_param (&d, chain_next, "chain_next"); + oprintf (d.of, ");\n"); if (chain_prev != NULL) { - oprintf (f, " if (x != xlimit)\n"); - oprintf (f, " for (;;)\n"); - oprintf (f, " {\n"); - oprintf (f, " %s %s * const xprev = (", + oprintf (d.of, " if (x != xlimit)\n"); + oprintf (d.of, " for (;;)\n"); + oprintf (d.of, " {\n"); + oprintf (d.of, " %s %s * const xprev = (", s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag); - output_escaped_param (f, chain_prev, "*x", "*x", - "chain_prev", &s->u.s.line); - oprintf (f, ");\n"); - oprintf (f, " if (xprev == NULL) break;\n"); - oprintf (f, " x = xprev;\n"); - oprintf (f, " ggc_set_mark (xprev);\n"); - oprintf (f, " }\n"); + + d.prev_val[2] = "*x"; + output_escaped_param (&d, chain_prev, "chain_prev"); + oprintf (d.of, ");\n"); + oprintf (d.of, " if (xprev == NULL) break;\n"); + oprintf (d.of, " x = xprev;\n"); + oprintf (d.of, " (void) %s (xprev", + wtd->marker_routine); + if (wtd->param_prefix) + { + oprintf (d.of, ", xprev, gt_%s_", wtd->param_prefix); + output_mangled_typename (d.of, orig_s); + } + oprintf (d.of, ");\n"); + oprintf (d.of, " }\n"); } - oprintf (f, " while (x != xlimit)\n"); + oprintf (d.of, " while (x != xlimit)\n"); } - oprintf (f, " {\n"); + oprintf (d.of, " {\n"); - gc_counter = 0; - write_gc_structure_fields (f, s, "(*x)", "not valid postage", - s->u.s.opt, 6, &s->u.s.line, s->u.s.bitmap, - param); + d.prev_val[2] = "*x"; + d.indent = 6; + walk_type (s, &d); if (chain_next != NULL) { - oprintf (f, " x = ("); - output_escaped_param (f, chain_next, "*x", "*x", - "chain_next", &s->u.s.line); - oprintf (f, ");\n"); + oprintf (d.of, " x = ("); + output_escaped_param (&d, chain_next, "chain_next"); + oprintf (d.of, ");\n"); } - oprintf (f, " }\n"); - oprintf (f, "}\n"); + oprintf (d.of, " }\n"); + oprintf (d.of, "}\n"); } /* Write out marker routines for STRUCTURES and PARAM_STRUCTS. */ static void -write_gc_types (structures, param_structs) +write_types (structures, param_structs, wtd) type_p structures; type_p param_structs; + const struct write_types_data *wtd; { type_p s; - oprintf (header_file, "\n/* GC marker procedures. */\n"); + oprintf (header_file, "\n/* %s*/\n", wtd->comment); for (s = structures; s; s = s->next) if (s->gc_used == GC_POINTED_TO || s->gc_used == GC_MAYBE_POINTED_TO) @@ -1988,11 +2090,12 @@ write_gc_types (structures, param_structs) && s->u.s.line.file == NULL) continue; - oprintf (header_file, "#define gt_ggc_m_"); + oprintf (header_file, "#define gt_%s_", wtd->prefix); output_mangled_typename (header_file, s); oprintf (header_file, "(X) do { \\\n"); oprintf (header_file, - " if (X != NULL) gt_ggc_mx_%s (X);\\\n", s->u.s.tag); + " if (X != NULL) gt_%sx_%s (X);\\\n", wtd->prefix, + s->u.s.tag); oprintf (header_file, " } while (0)\n"); @@ -2004,8 +2107,8 @@ write_gc_types (structures, param_structs) || t->kind == TYPE_UNION || t->kind == TYPE_LANG_STRUCT) oprintf (header_file, - "#define gt_ggc_mx_%s gt_ggc_mx_%s\n", - s->u.s.tag, t->u.s.tag); + "#define gt_%sx_%s gt_%sx_%s\n", + wtd->prefix, s->u.s.tag, wtd->prefix, t->u.s.tag); else error_at_line (&s->u.s.line, "structure alias is not a structure"); @@ -2016,8 +2119,8 @@ write_gc_types (structures, param_structs) /* Declare the marker procedure only once. */ oprintf (header_file, - "extern void gt_ggc_mx_%s PARAMS ((void *));\n", - s->u.s.tag); + "extern void gt_%sx_%s PARAMS ((void *));\n", + wtd->prefix, s->u.s.tag); if (s->u.s.line.file == NULL) { @@ -2030,10 +2133,10 @@ write_gc_types (structures, param_structs) { type_p ss; for (ss = s->u.s.lang_struct; ss; ss = ss->next) - write_gc_marker_routine_for_structure (s, ss, NULL); + write_func_for_structure (s, ss, NULL, wtd); } else - write_gc_marker_routine_for_structure (s, s, NULL); + write_func_for_structure (s, s, NULL, wtd); } for (s = param_structs; s; s = s->next) @@ -2043,7 +2146,7 @@ write_gc_types (structures, param_structs) type_p stru = s->u.param_struct.stru; /* Declare the marker procedure. */ - oprintf (header_file, "extern void gt_ggc_m_"); + oprintf (header_file, "extern void gt_%s_", wtd->prefix); output_mangled_typename (header_file, s); oprintf (header_file, " PARAMS ((void *));\n"); @@ -2058,10 +2161,193 @@ write_gc_types (structures, param_structs) { type_p ss; for (ss = stru->u.s.lang_struct; ss; ss = ss->next) - write_gc_marker_routine_for_structure (s, ss, param); + write_func_for_structure (s, ss, param, wtd); + } + else + write_func_for_structure (s, stru, param, wtd); + } +} + +static const struct write_types_data ggc_wtd = +{ + "ggc_m", NULL, "ggc_mark", "ggc_test_and_set_mark", NULL, + "GC marker procedures. " +}; + +static const struct write_types_data pch_wtd = +{ + "pch_n", "pch_p", "gt_pch_note_object", "gt_pch_note_object", + "gt_pch_note_reorder", + "PCH type-walking procedures. " +}; + +/* Write out the local pointer-walking routines. */ + +/* process_field routine for local pointer-walking. */ + +static void +write_types_local_process_field (f, d) + 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, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "", + d->prev_val[3]); + oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); + break; + + case TYPE_SCALAR: + break; + + default: + abort (); + } +} + +/* 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 + - If calls PROCESS_FIELD on each field of S or its substructures. +*/ + +static void +write_local_func_for_structure (orig_s, s, param) + type_p orig_s; + type_p s; + type_p * param; +{ + const char *fn = s->u.s.line.file; + int i; + struct walk_type_data d; + + /* This is a hack, and not the good kind either. */ + for (i = NUM_PARAM - 1; i >= 0; i--) + if (param && param[i] && param[i]->kind == TYPE_POINTER + && UNION_OR_STRUCT_P (param[i]->u.p)) + fn = param[i]->u.p->u.s.line.file; + + memset (&d, 0, sizeof (d)); + d.of = get_output_file_with_visibility (fn); + + d.process_field = write_types_local_process_field; + d.opt = s->u.s.opt; + d.line = &s->u.s.line; + d.bitmap = s->u.s.bitmap; + d.param = param; + d.prev_val[0] = d.prev_val[2] = "*x"; + d.prev_val[1] = "not valid postage"; /* guarantee an error */ + d.prev_val[3] = "x"; + d.val = "(*x)"; + + oprintf (d.of, "\n"); + oprintf (d.of, "void\n"); + oprintf (d.of, "gt_pch_p_"); + output_mangled_typename (d.of, orig_s); + oprintf (d.of, " (this_obj, x_p, op, cookie)\n"); + oprintf (d.of, " void *this_obj ATTRIBUTE_UNUSED;\n"); + oprintf (d.of, " void *x_p;\n"); + oprintf (d.of, " gt_pointer_operator op ATTRIBUTE_UNUSED;\n"); + oprintf (d.of, " void *cookie ATTRIBUTE_UNUSED;\n"); + oprintf (d.of, "{\n"); + oprintf (d.of, " %s %s * const x ATTRIBUTE_UNUSED = (%s %s *)x_p;\n", + s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag, + s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag); + d.indent = 2; + walk_type (s, &d); + oprintf (d.of, "}\n"); +} + +/* Write out local marker routines for STRUCTURES and PARAM_STRUCTS. */ + +static void +write_local (structures, param_structs) + type_p structures; + type_p param_structs; +{ + type_p s; + + oprintf (header_file, "\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) + { + options_p opt; + + if (s->u.s.line.file == NULL) + continue; + + for (opt = s->u.s.opt; opt; opt = opt->next) + if (strcmp (opt->name, "ptr_alias") == 0) + { + type_p t = (type_p) opt->info; + if (t->kind == TYPE_STRUCT + || t->kind == TYPE_UNION + || t->kind == TYPE_LANG_STRUCT) + { + oprintf (header_file, "#define gt_pch_p_"); + output_mangled_typename (header_file, s); + oprintf (header_file, " gt_pch_p_"); + output_mangled_typename (header_file, t); + oprintf (header_file, "\n"); + } + else + error_at_line (&s->u.s.line, + "structure alias is not a structure"); + break; + } + if (opt) + continue; + + /* Declare the marker procedure only once. */ + oprintf (header_file, "extern void gt_pch_p_"); + output_mangled_typename (header_file, s); + oprintf (header_file, + "\n PARAMS ((void *, void *, gt_pointer_operator, void *));\n"); + + if (s->kind == TYPE_LANG_STRUCT) + { + type_p ss; + for (ss = s->u.s.lang_struct; ss; ss = ss->next) + write_local_func_for_structure (s, ss, NULL); + } + else + write_local_func_for_structure (s, s, NULL); + } + + for (s = param_structs; s; s = s->next) + if (s->gc_used == GC_POINTED_TO) + { + type_p * param = s->u.param_struct.param; + type_p stru = s->u.param_struct.stru; + + /* Declare the marker procedure. */ + oprintf (header_file, "extern void gt_pch_p_"); + output_mangled_typename (header_file, s); + oprintf (header_file, + "\n PARAMS ((void *, void *, gt_pointer_operator, void *));\n"); + + if (stru->u.s.line.file == NULL) + { + fprintf (stderr, "warning: structure `%s' used but not defined\n", + s->u.s.tag); + continue; + } + + if (stru->kind == TYPE_LANG_STRUCT) + { + type_p ss; + for (ss = stru->u.s.lang_struct; ss; ss = ss->next) + write_local_func_for_structure (s, ss, param); } else - write_gc_marker_routine_for_structure (s, stru, param); + write_local_func_for_structure (s, stru, param); } } @@ -2099,6 +2385,25 @@ write_enum_defn (structures, param_structs) oprintf (header_file, "};\n"); } +/* Might T contain any non-pointer elements? */ + +static int +contains_scalar_p (t) + type_p t; +{ + switch (t->kind) + { + case TYPE_STRING: + case TYPE_POINTER: + return 0; + case TYPE_ARRAY: + return contains_scalar_p (t->u.a.p); + default: + /* Could also check for structures that have no non-pointer + fields, but there aren't enough of those to worry about. */ + return 1; + } +} /* Mangle FN and print it to F. */ @@ -2128,7 +2433,6 @@ finish_root_table (flp, pfx, lastname, tname, name) const char *name; { struct flist *fli2; - unsigned started_bitmap = 0; for (fli2 = flp; fli2; fli2 = fli2->next) if (fli2->started_p) @@ -2147,12 +2451,21 @@ finish_root_table (flp, pfx, lastname, tname, name) if (bitmap & 1) { oprintf (base_files[fnum], - "extern const struct %s gt_ggc_%s_", + "extern const struct %s gt_%s_", tname, pfx); put_mangled_filename (base_files[fnum], fli2->name); oprintf (base_files[fnum], "[];\n"); } } + + { + size_t fnum; + for (fnum = 0; fnum < NUM_BASE_FILES; fnum++) + oprintf (base_files [fnum], + "const struct %s * const %s[] = {\n", + tname, name); + } + for (fli2 = flp; fli2; fli2 = fli2->next) if (fli2->started_p) @@ -2165,29 +2478,19 @@ finish_root_table (flp, pfx, lastname, tname, name) for (fnum = 0; bitmap != 0; fnum++, bitmap >>= 1) if (bitmap & 1) { - if (! (started_bitmap & (1 << fnum))) - { - oprintf (base_files [fnum], - "const struct %s * const %s[] = {\n", - tname, name); - started_bitmap |= 1 << fnum; - } - oprintf (base_files[fnum], " gt_ggc_%s_", pfx); + oprintf (base_files[fnum], " gt_%s_", pfx); put_mangled_filename (base_files[fnum], fli2->name); oprintf (base_files[fnum], ",\n"); } } { - unsigned bitmap; - int fnum; - - for (bitmap = started_bitmap, fnum = 0; bitmap != 0; fnum++, bitmap >>= 1) - if (bitmap & 1) - { - oprintf (base_files[fnum], " NULL\n"); - oprintf (base_files[fnum], "};\n"); - } + size_t fnum; + for (fnum = 0; fnum < NUM_BASE_FILES; fnum++) + { + oprintf (base_files[fnum], " NULL\n"); + oprintf (base_files[fnum], "};\n"); + } } } @@ -2197,7 +2500,7 @@ finish_root_table (flp, pfx, lastname, tname, name) is nonzero iff we are building the root table for hash table caches. */ static void -write_gc_root (f, v, type, name, has_length, line, if_marked) +write_root (f, v, type, name, has_length, line, if_marked) outf_p f; pair_p v; type_p type; @@ -2257,8 +2560,8 @@ write_gc_root (f, v, type, name, has_length, line, if_marked) char *newname; newname = xasprintf ("%s.%s.%s", name, fld->name, validf->name); - write_gc_root (f, v, validf->type, newname, 0, line, - if_marked); + write_root (f, v, validf->type, newname, 0, line, + if_marked); free (newname); } } @@ -2270,7 +2573,7 @@ write_gc_root (f, v, type, name, has_length, line, if_marked) { char *newname; newname = xasprintf ("%s.%s", name, fld->name); - write_gc_root (f, v, fld->type, newname, 0, line, if_marked); + write_root (f, v, fld->type, newname, 0, line, if_marked); free (newname); } } @@ -2281,7 +2584,7 @@ write_gc_root (f, v, type, name, has_length, line, if_marked) { char *newname; newname = xasprintf ("%s[0]", name); - write_gc_root (f, v, type->u.a.p, newname, has_length, line, if_marked); + write_root (f, v, type->u.a.p, newname, has_length, line, if_marked); free (newname); } break; @@ -2309,17 +2612,21 @@ write_gc_root (f, v, type, name, has_length, line, if_marked) if (! has_length && UNION_OR_STRUCT_P (tp)) { - oprintf (f, " >_ggc_mx_%s\n", tp->u.s.tag); + oprintf (f, " >_ggc_mx_%s,\n", tp->u.s.tag); + oprintf (f, " >_pch_nx_%s", tp->u.s.tag); } else if (! has_length && tp->kind == TYPE_PARAM_STRUCT) { oprintf (f, " >_ggc_m_"); output_mangled_typename (f, tp); + oprintf (f, ",\n >_pch_n_"); + output_mangled_typename (f, tp); } else if (has_length && (tp->kind == TYPE_POINTER || UNION_OR_STRUCT_P (tp))) { - oprintf (f, " >_ggc_ma_%s", name); + oprintf (f, " >_ggc_ma_%s,\n", name); + oprintf (f, " >_pch_na_%s", name); } else { @@ -2333,8 +2640,19 @@ write_gc_root (f, v, type, name, has_length, line, if_marked) } break; - case TYPE_SCALAR: case TYPE_STRING: + { + oprintf (f, " {\n"); + oprintf (f, " &%s,\n", name); + oprintf (f, " 1, \n"); + oprintf (f, " sizeof (%s),\n", v->name); + oprintf (f, " >_ggc_m_S,\n"); + oprintf (f, " >_pch_n_S\n"); + oprintf (f, " },\n"); + } + break; + + case TYPE_SCALAR: break; default: @@ -2344,10 +2662,64 @@ write_gc_root (f, v, type, name, has_length, line, if_marked) } } +/* This generates a routine to walk an array. */ + +static void +write_array (f, v, wtd) + outf_p f; + pair_p v; + const struct write_types_data *wtd; +{ + struct walk_type_data d; + char *prevval3; + + memset (&d, 0, sizeof (d)); + d.of = f; + d.cookie = wtd; + d.indent = 2; + d.line = &v->line; + d.opt = v->opt; + d.bitmap = get_base_file_bitmap (v->line.file); + d.param = NULL; + + d.prev_val[3] = prevval3 = xasprintf ("&%s", v->name); + + if (wtd->param_prefix) + { + oprintf (f, "static void gt_%sa_%s\n", wtd->param_prefix, v->name); + oprintf (f, + " PARAMS ((void *, void *, gt_pointer_operator, void *));\n"); + oprintf (f, "static void gt_%sa_%s (this_obj, x_p, op, cookie)\n", + wtd->param_prefix, v->name); + oprintf (d.of, " void *this_obj ATTRIBUTE_UNUSED;\n"); + oprintf (d.of, " void *x_p ATTRIBUTE_UNUSED;\n"); + oprintf (d.of, " gt_pointer_operator op ATTRIBUTE_UNUSED;\n"); + oprintf (d.of, " void *cookie ATTRIBUTE_UNUSED;\n"); + oprintf (d.of, "{\n"); + d.prev_val[0] = d.prev_val[1] = d.prev_val[2] = d.val = v->name; + d.process_field = write_types_local_process_field; + walk_type (v->type, &d); + oprintf (f, "}\n\n"); + } + + d.opt = v->opt; + oprintf (f, "static void gt_%sa_%s PARAMS ((void *));\n", + wtd->prefix, v->name); + oprintf (f, "static void\ngt_%sa_%s (x_p)\n", + wtd->prefix, v->name); + oprintf (f, " void *x_p ATTRIBUTE_UNUSED;\n"); + oprintf (f, "{\n"); + d.prev_val[0] = d.prev_val[1] = d.prev_val[2] = d.val = v->name; + d.process_field = write_types_process_field; + walk_type (v->type, &d); + free (prevval3); + oprintf (f, "}\n\n"); +} + /* Output a table describing the locations and types of VARIABLES. */ static void -write_gc_roots (variables) +write_roots (variables) pair_p variables; { pair_p v; @@ -2400,52 +2772,8 @@ write_gc_roots (variables) && (v->type->u.p->kind == TYPE_POINTER || v->type->u.p->kind == TYPE_STRUCT)) { - oprintf (f, "static void gt_ggc_ma_%s PARAMS ((void *));\n", - v->name); - oprintf (f, "static void\ngt_ggc_ma_%s (x_p)\n void *x_p;\n", - v->name); - oprintf (f, "{\n"); - oprintf (f, " size_t i;\n"); - - if (v->type->u.p->kind == TYPE_POINTER) - { - type_p s = v->type->u.p->u.p; - - oprintf (f, " %s %s ** const x = (%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); - oprintf (f, " if (ggc_test_and_set_mark (x))\n"); - oprintf (f, " for (i = 0; i < (%s); i++)\n", length); - if (! UNION_OR_STRUCT_P (s) - && ! s->kind == TYPE_PARAM_STRUCT) - { - error_at_line (&v->line, - "global `%s' has unsupported ** type", - v->name); - continue; - } - - oprintf (f, " gt_ggc_m_"); - output_mangled_typename (f, s); - oprintf (f, " (x[i]);\n"); - } - else - { - type_p s = v->type->u.p; - - oprintf (f, " %s %s * const x = (%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); - oprintf (f, " if (ggc_test_and_set_mark (x))\n"); - oprintf (f, " for (i = 0; i < (%s); i++)\n", length); - oprintf (f, " {\n"); - write_gc_structure_fields (f, s, "x[i]", "x[i]", - v->opt, 8, &v->line, s->u.s.bitmap, - NULL); - oprintf (f, " }\n"); - } - - oprintf (f, "}\n\n"); + write_array (f, v, &ggc_wtd); + write_array (f, v, &pch_wtd); } } @@ -2479,10 +2807,10 @@ write_gc_roots (variables) oprintf (f, "[] = {\n"); } - write_gc_root (f, v, v->type, v->name, length_p, &v->line, NULL); + write_root (f, v, v->type, v->name, length_p, &v->line, NULL); } - finish_root_table (flp, "r", "LAST_GGC_ROOT_TAB", "ggc_root_tab", + finish_root_table (flp, "ggc_r", "LAST_GGC_ROOT_TAB", "ggc_root_tab", "gt_ggc_rtab"); for (v = variables; v; v = v->next) @@ -2513,11 +2841,11 @@ write_gc_roots (variables) oprintf (f, "[] = {\n"); } - oprintf (f, " { &%s, 1, sizeof (%s), NULL },\n", + oprintf (f, " { &%s, 1, sizeof (%s), NULL, NULL },\n", v->name, v->name); } - finish_root_table (flp, "rd", "LAST_GGC_ROOT_TAB", "ggc_root_tab", + finish_root_table (flp, "ggc_rd", "LAST_GGC_ROOT_TAB", "ggc_root_tab", "gt_ggc_deletable_rtab"); for (v = variables; v; v = v->next) @@ -2557,12 +2885,84 @@ write_gc_roots (variables) oprintf (f, "[] = {\n"); } - write_gc_root (f, v, v->type->u.p->u.param_struct.param[0], + write_root (f, v, v->type->u.p->u.param_struct.param[0], v->name, length_p, &v->line, if_marked); } - finish_root_table (flp, "rc", "LAST_GGC_CACHE_TAB", "ggc_cache_tab", + finish_root_table (flp, "ggc_rc", "LAST_GGC_CACHE_TAB", "ggc_cache_tab", "gt_ggc_cache_rtab"); + + for (v = variables; v; v = v->next) + { + outf_p f = get_output_file_with_visibility (v->line.file); + struct flist *fli; + int length_p = 0; + int if_marked_p = 0; + options_p o; + + for (o = v->opt; o; o = o->next) + if (strcmp (o->name, "length") == 0) + length_p = 1; + else if (strcmp (o->name, "if_marked") == 0) + if_marked_p = 1; + + if (! if_marked_p) + continue; + + for (fli = flp; fli; fli = fli->next) + if (fli->f == f) + break; + if (! fli->started_p) + { + fli->started_p = 1; + + oprintf (f, "const struct ggc_root_tab gt_pch_rc_"); + put_mangled_filename (f, v->line.file); + oprintf (f, "[] = {\n"); + } + + write_root (f, v, v->type, v->name, length_p, &v->line, NULL); + } + + finish_root_table (flp, "pch_rc", "LAST_GGC_ROOT_TAB", "ggc_root_tab", + "gt_pch_cache_rtab"); + + for (v = variables; v; v = v->next) + { + outf_p f = get_output_file_with_visibility (v->line.file); + struct flist *fli; + int skip_p = 0; + options_p o; + + for (o = v->opt; o; o = o->next) + if (strcmp (o->name, "deletable") == 0 + || strcmp (o->name, "if_marked") == 0) + skip_p = 1; + + if (skip_p) + continue; + + if (! contains_scalar_p (v->type)) + continue; + + for (fli = flp; fli; fli = fli->next) + if (fli->f == f) + break; + if (! fli->started_p) + { + fli->started_p = 1; + + oprintf (f, "const struct ggc_root_tab gt_pch_rs_"); + put_mangled_filename (f, v->line.file); + oprintf (f, "[] = {\n"); + } + + oprintf (f, " { &%s, 1, sizeof (%s), NULL, NULL },\n", + v->name, v->name); + } + + finish_root_table (flp, "pch_rs", "LAST_GGC_ROOT_TAB", "ggc_root_tab", + "gt_pch_scalar_rtab"); } @@ -2616,8 +3016,10 @@ main(argc, argv) open_base_files (); write_enum_defn (structures, param_structs); - write_gc_types (structures, param_structs); - write_gc_roots (variables); + write_types (structures, param_structs, &ggc_wtd); + write_types (structures, param_structs, &pch_wtd); + write_local (structures, param_structs); + write_roots (variables); write_rtx_next (); close_output_files (); diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c index f353617..ed6d3b4 100644 --- a/gcc/ggc-common.c +++ b/gcc/ggc-common.c @@ -24,14 +24,14 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "config.h" #include "system.h" #include "coretypes.h" -#include "tm.h" -#include "rtl.h" -#include "tree.h" -#include "tm_p.h" #include "hashtab.h" -#include "varray.h" #include "ggc.h" -#include "langhooks.h" +#include "toplev.h" + +#ifdef HAVE_MMAP_FILE +# include +#endif + #ifdef ENABLE_VALGRIND_CHECKING #include #else @@ -42,46 +42,20 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA /* Statistics about the allocation. */ static ggc_statistics *ggc_stats; +struct traversal_state; + static int ggc_htab_delete PARAMS ((void **, void *)); +static hashval_t saving_htab_hash PARAMS ((const PTR)); +static int saving_htab_eq PARAMS ((const PTR, const PTR)); +static int call_count PARAMS ((void **, void *)); +static int call_alloc PARAMS ((void **, void *)); +static int compare_ptr_data PARAMS ((const void *, const void *)); +static void relocate_ptrs PARAMS ((void *, void *)); +static void write_pch_globals PARAMS ((const struct ggc_root_tab * const *tab, + struct traversal_state *state)); /* Maintain global roots that are preserved during GC. */ -/* Global roots that are preserved during calls to gc. */ - -struct ggc_root -{ - struct ggc_root *next; - void *base; - int nelt; - int size; - void (*cb) PARAMS ((void *)); -}; - -static struct ggc_root *roots; - -/* Add BASE as a new garbage collection root. It is an array of - length NELT with each element SIZE bytes long. CB is a - function that will be called with a pointer to each element - of the array; it is the intention that CB call the appropriate - routine to mark gc-able memory for that element. */ - -void -ggc_add_root (base, nelt, size, cb) - void *base; - int nelt, size; - void (*cb) PARAMS ((void *)); -{ - struct ggc_root *x = (struct ggc_root *) xmalloc (sizeof (*x)); - - x->next = roots; - x->base = base; - x->nelt = nelt; - x->size = size; - x->cb = cb; - - roots = x; -} - /* Process a slot of an htab by deleting it if it has not been marked. */ static int @@ -104,7 +78,6 @@ ggc_htab_delete (slot, info) void ggc_mark_roots () { - struct ggc_root *x; const struct ggc_root_tab *const *rt; const struct ggc_root_tab *rti; const struct ggc_cache_tab *const *ct; @@ -120,23 +93,18 @@ ggc_mark_roots () for (i = 0; i < rti->nelt; i++) (*rti->cb)(*(void **)((char *)rti->base + rti->stride * i)); - for (x = roots; x != NULL; x = x->next) - { - char *elt = x->base; - int s = x->size, n = x->nelt; - void (*cb) PARAMS ((void *)) = x->cb; - int i; - - for (i = 0; i < n; ++i, elt += s) - (*cb)(elt); - } + ggc_mark_stringpool (); /* Now scan all hash tables that have objects which are to be deleted if they are not already marked. */ for (ct = gt_ggc_cache_rtab; *ct; ct++) for (cti = *ct; cti->base != NULL; cti++) if (*cti->base) - htab_traverse (*cti->base, ggc_htab_delete, (PTR) cti); + { + ggc_set_mark (*cti->base); + htab_traverse (*cti->base, ggc_htab_delete, (PTR) cti); + ggc_set_mark ((*cti->base)->entries); + } } /* Allocate a block of memory, then clear it. */ @@ -204,6 +172,26 @@ ggc_calloc (s1, s2) return ggc_alloc_cleared (s1 * s2); } +/* These are for splay_tree_new_ggc. */ +PTR +ggc_splay_alloc (sz, nl) + int sz; + PTR nl; +{ + if (nl != NULL) + abort (); + return ggc_alloc (sz); +} + +void +ggc_splay_dont_free (x, nl) + PTR x ATTRIBUTE_UNUSED; + PTR nl; +{ + if (nl != NULL) + abort (); +} + /* Print statistics that are independent of the collector in use. */ #define SCALE(x) ((unsigned long) ((x) < 1024*10 \ ? (x) \ @@ -214,11 +202,9 @@ ggc_calloc (s1, s2) void ggc_print_common_statistics (stream, stats) - FILE *stream; + FILE *stream ATTRIBUTE_UNUSED; ggc_statistics *stats; { - int code; - /* Set the pointer so that during collection we will actually gather the statistics. */ ggc_stats = stats; @@ -226,58 +212,415 @@ ggc_print_common_statistics (stream, stats) /* Then do one collection to fill in the statistics. */ ggc_collect (); - /* Total the statistics. */ - for (code = 0; code < MAX_TREE_CODES; ++code) + /* At present, we don't really gather any interesting statistics. */ + + /* Don't gather statistics any more. */ + ggc_stats = NULL; +} + +/* Functions for saving and restoring GCable memory to disk. */ + +static htab_t saving_htab; + +struct ptr_data +{ + void *obj; + void *note_ptr_cookie; + gt_note_pointers note_ptr_fn; + gt_handle_reorder reorder_fn; + size_t size; + void *new_addr; +}; + +#define POINTER_HASH(x) (hashval_t)((long)x >> 3) + +/* Register an object in the hash table. */ + +int +gt_pch_note_object (obj, note_ptr_cookie, note_ptr_fn) + void *obj; + void *note_ptr_cookie; + gt_note_pointers note_ptr_fn; +{ + struct ptr_data **slot; + + if (obj == NULL || obj == (void *) 1) + return 0; + + slot = (struct ptr_data **) + htab_find_slot_with_hash (saving_htab, obj, POINTER_HASH (obj), + INSERT); + if (*slot != NULL) + { + if ((*slot)->note_ptr_fn != note_ptr_fn + || (*slot)->note_ptr_cookie != note_ptr_cookie) + abort (); + return 0; + } + + *slot = xcalloc (sizeof (struct ptr_data), 1); + (*slot)->obj = obj; + (*slot)->note_ptr_fn = note_ptr_fn; + (*slot)->note_ptr_cookie = note_ptr_cookie; + if (note_ptr_fn == gt_pch_p_S) + (*slot)->size = strlen (obj) + 1; + else + (*slot)->size = ggc_get_size (obj); + return 1; +} + +/* Register an object in the hash table. */ + +void +gt_pch_note_reorder (obj, note_ptr_cookie, reorder_fn) + void *obj; + void *note_ptr_cookie; + gt_handle_reorder reorder_fn; +{ + struct ptr_data *data; + + if (obj == NULL || obj == (void *) 1) + return; + + data = htab_find_with_hash (saving_htab, obj, POINTER_HASH (obj)); + if (data == NULL + || data->note_ptr_cookie != note_ptr_cookie) + abort (); + + data->reorder_fn = reorder_fn; +} + +/* Hash and equality functions for saving_htab, callbacks for htab_create. */ + +static hashval_t +saving_htab_hash (p) + const PTR p; +{ + return POINTER_HASH (((struct ptr_data *)p)->obj); +} + +static int +saving_htab_eq (p1, p2) + const PTR p1; + const PTR p2; +{ + return ((struct ptr_data *)p1)->obj == p2; +} + +/* Handy state for the traversal functions. */ + +struct traversal_state +{ + FILE *f; + struct ggc_pch_data *d; + size_t count; + struct ptr_data **ptrs; + size_t ptrs_i; +}; + +/* Callbacks for htab_traverse. */ + +static int +call_count (slot, state_p) + void **slot; + void *state_p; +{ + struct ptr_data *d = (struct ptr_data *)*slot; + struct traversal_state *state = (struct traversal_state *)state_p; + + ggc_pch_count_object (state->d, d->obj, d->size); + state->count++; + return 1; +} + +static int +call_alloc (slot, state_p) + void **slot; + void *state_p; +{ + struct ptr_data *d = (struct ptr_data *)*slot; + struct traversal_state *state = (struct traversal_state *)state_p; + + d->new_addr = ggc_pch_alloc_object (state->d, d->obj, d->size); + state->ptrs[state->ptrs_i++] = d; + return 1; +} + +/* Callback for qsort. */ + +static int +compare_ptr_data (p1_p, p2_p) + const void *p1_p; + const void *p2_p; +{ + struct ptr_data *p1 = *(struct ptr_data *const *)p1_p; + struct ptr_data *p2 = *(struct ptr_data *const *)p2_p; + return (((size_t)p1->new_addr > (size_t)p2->new_addr) + - ((size_t)p1->new_addr < (size_t)p2->new_addr)); +} + +/* Callbacks for note_ptr_fn. */ + +static void +relocate_ptrs (ptr_p, state_p) + void *ptr_p; + void *state_p; +{ + void **ptr = (void **)ptr_p; + struct traversal_state *state ATTRIBUTE_UNUSED + = (struct traversal_state *)state_p; + struct ptr_data *result; + + if (*ptr == NULL || *ptr == (void *)1) + return; + + result = htab_find_with_hash (saving_htab, *ptr, POINTER_HASH (*ptr)); + if (result == NULL) + abort (); + *ptr = result->new_addr; +} + +/* Write out, after relocation, the pointers in TAB. */ +static void +write_pch_globals (tab, state) + const struct ggc_root_tab * const *tab; + struct traversal_state *state; +{ + const struct ggc_root_tab *const *rt; + const struct ggc_root_tab *rti; + size_t i; + + for (rt = tab; *rt; rt++) + for (rti = *rt; rti->base != NULL; rti++) + for (i = 0; i < rti->nelt; i++) + { + void *ptr = *(void **)((char *)rti->base + rti->stride * i); + struct ptr_data *new_ptr; + if (ptr == NULL || ptr == (void *)1) + { + if (fwrite (&ptr, sizeof (void *), 1, state->f) + != 1) + fatal_io_error ("can't write PCH file"); + } + else + { + new_ptr = htab_find_with_hash (saving_htab, ptr, + POINTER_HASH (ptr)); + if (fwrite (&new_ptr->new_addr, sizeof (void *), 1, state->f) + != 1) + fatal_io_error ("can't write PCH file"); + } + } +} + +/* Hold the information we need to mmap the file back in. */ + +struct mmap_info +{ + size_t offset; + size_t size; + void *preferred_base; +}; + +/* Write out the state of the compiler to F. */ + +void +gt_pch_save (f) + FILE *f; +{ + const struct ggc_root_tab *const *rt; + const struct ggc_root_tab *rti; + size_t i; + struct traversal_state state; + char *this_object = NULL; + size_t this_object_size = 0; + struct mmap_info mmi; + size_t page_size = getpagesize(); + + gt_pch_save_stringpool (); + + saving_htab = htab_create (50000, saving_htab_hash, saving_htab_eq, free); + + for (rt = gt_ggc_rtab; *rt; rt++) + for (rti = *rt; rti->base != NULL; rti++) + for (i = 0; i < rti->nelt; i++) + (*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i)); + + for (rt = gt_pch_cache_rtab; *rt; rt++) + for (rti = *rt; rti->base != NULL; rti++) + for (i = 0; i < rti->nelt; i++) + (*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i)); + + /* Prepare the objects for writing, determine addresses and such. */ + state.f = f; + state.d = init_ggc_pch(); + state.count = 0; + htab_traverse (saving_htab, call_count, &state); + + mmi.size = ggc_pch_total_size (state.d); + + /* Try to arrange things so that no relocation is necessary, + but don't try very hard. On most platforms, this will always work, + and on the rest it's a lot of work to do better. */ +#if HAVE_MMAP_FILE + mmi.preferred_base = mmap (NULL, mmi.size, + PROT_READ | PROT_WRITE, MAP_PRIVATE, + fileno (state.f), 0); + if (mmi.preferred_base == (void *)-1) + mmi.preferred_base = NULL; + else + munmap (mmi.preferred_base, mmi.size); +#else /* HAVE_MMAP_FILE */ + mmi.preferred_base = NULL; +#endif /* HAVE_MMAP_FILE */ + + ggc_pch_this_base (state.d, mmi.preferred_base); + + state.ptrs = xmalloc (state.count * sizeof (*state.ptrs)); + state.ptrs_i = 0; + htab_traverse (saving_htab, call_alloc, &state); + qsort (state.ptrs, state.count, sizeof (*state.ptrs), compare_ptr_data); + + /* Write out all the scalar variables. */ + for (rt = gt_pch_scalar_rtab; *rt; rt++) + for (rti = *rt; rti->base != NULL; rti++) + if (fwrite (rti->base, rti->stride, 1, f) != 1) + fatal_io_error ("can't write PCH file"); + + /* Write out all the global pointers, after translation. */ + write_pch_globals (gt_ggc_rtab, &state); + write_pch_globals (gt_pch_cache_rtab, &state); + + ggc_pch_prepare_write (state.d, state.f); + + /* Pad the PCH file so that the mmaped area starts on a page boundary. */ + { + off_t o; + o = ftello (state.f) + sizeof (mmi); + if (o == (off_t) -1) + fatal_io_error ("can't get position in PCH file"); + mmi.offset = page_size - o % page_size; + if (mmi.offset == page_size) + mmi.offset = 0; + mmi.offset += o; + } + if (fwrite (&mmi, sizeof (mmi), 1, state.f) != 1) + fatal_io_error ("can't write PCH file"); + if (mmi.offset != 0 + && fseek (state.f, mmi.offset, SEEK_SET) != 0) + fatal_io_error ("can't write padding to PCH file"); + + /* Actually write out the objects. */ + for (i = 0; i < state.count; i++) { - stats->total_num_trees += stats->num_trees[code]; - stats->total_size_trees += stats->size_trees[code]; + if (this_object_size < state.ptrs[i]->size) + { + this_object_size = state.ptrs[i]->size; + this_object = xrealloc (this_object, this_object_size); + } + memcpy (this_object, state.ptrs[i]->obj, state.ptrs[i]->size); + if (state.ptrs[i]->reorder_fn != NULL) + state.ptrs[i]->reorder_fn (state.ptrs[i]->obj, + state.ptrs[i]->note_ptr_cookie, + relocate_ptrs, &state); + state.ptrs[i]->note_ptr_fn (state.ptrs[i]->obj, + state.ptrs[i]->note_ptr_cookie, + relocate_ptrs, &state); + ggc_pch_write_object (state.d, state.f, state.ptrs[i]->obj, + state.ptrs[i]->new_addr, state.ptrs[i]->size); + if (state.ptrs[i]->note_ptr_fn != gt_pch_p_S) + memcpy (state.ptrs[i]->obj, this_object, state.ptrs[i]->size); } - for (code = 0; code < NUM_RTX_CODE; ++code) + ggc_pch_finish (state.d, state.f); + + free (state.ptrs); + htab_delete (saving_htab); +} + +/* Read the state of the compiler back in from F. */ + +void +gt_pch_restore (f) + FILE *f; +{ + const struct ggc_root_tab *const *rt; + const struct ggc_root_tab *rti; + size_t i; + struct mmap_info mmi; + void *addr; + + /* Delete any deletable objects. This makes ggc_pch_read much + faster, as it can be sure that no GCable objects remain other + than the ones just read in. */ + for (rt = gt_ggc_deletable_rtab; *rt; rt++) + for (rti = *rt; rti->base != NULL; rti++) + memset (rti->base, 0, rti->stride); + + /* Read in all the scalar variables. */ + for (rt = gt_pch_scalar_rtab; *rt; rt++) + for (rti = *rt; rti->base != NULL; rti++) + if (fread (rti->base, rti->stride, 1, f) != 1) + fatal_io_error ("can't read PCH file"); + + /* Read in all the global pointers, in 6 easy loops. */ + for (rt = gt_ggc_rtab; *rt; rt++) + for (rti = *rt; rti->base != NULL; rti++) + for (i = 0; i < rti->nelt; i++) + if (fread ((char *)rti->base + rti->stride * i, + sizeof (void *), 1, f) != 1) + fatal_io_error ("can't read PCH file"); + + for (rt = gt_pch_cache_rtab; *rt; rt++) + for (rti = *rt; rti->base != NULL; rti++) + for (i = 0; i < rti->nelt; i++) + if (fread ((char *)rti->base + rti->stride * i, + sizeof (void *), 1, f) != 1) + fatal_io_error ("can't read PCH file"); + + if (fread (&mmi, sizeof (mmi), 1, f) != 1) + fatal_io_error ("can't read PCH file"); + +#if HAVE_MMAP_FILE + addr = mmap (mmi.preferred_base, mmi.size, + PROT_READ | PROT_WRITE, MAP_PRIVATE, + fileno (f), mmi.offset); +#else + addr = (void *)-1; +#endif + if (addr == (void *)-1) { - stats->total_num_rtxs += stats->num_rtxs[code]; - stats->total_size_rtxs += stats->size_rtxs[code]; + addr = xmalloc (mmi.size); + if (fseek (f, mmi.offset, SEEK_SET) != 0 + || fread (&mmi, mmi.size, 1, f) != 1) + fatal_io_error ("can't read PCH file"); } + else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0) + fatal_io_error ("can't read PCH file"); - /* Print the statistics for trees. */ - fprintf (stream, "\n%-17s%10s %16s %10s\n", "Tree", - "Number", "Bytes", "% Total"); - for (code = 0; code < MAX_TREE_CODES; ++code) - if (ggc_stats->num_trees[code]) - { - fprintf (stream, "%-17s%10u%16ld%c %10.3f\n", - tree_code_name[code], - ggc_stats->num_trees[code], - SCALE (ggc_stats->size_trees[code]), - LABEL (ggc_stats->size_trees[code]), - (100 * ((double) ggc_stats->size_trees[code]) - / ggc_stats->total_size_trees)); - } - fprintf (stream, - "%-17s%10u%16ld%c\n", "Total", - ggc_stats->total_num_trees, - SCALE (ggc_stats->total_size_trees), - LABEL (ggc_stats->total_size_trees)); - - /* Print the statistics for RTL. */ - fprintf (stream, "\n%-17s%10s %16s %10s\n", "RTX", - "Number", "Bytes", "% Total"); - for (code = 0; code < NUM_RTX_CODE; ++code) - if (ggc_stats->num_rtxs[code]) - { - fprintf (stream, "%-17s%10u%16ld%c %10.3f\n", - rtx_name[code], - ggc_stats->num_rtxs[code], - SCALE (ggc_stats->size_rtxs[code]), - LABEL (ggc_stats->size_rtxs[code]), - (100 * ((double) ggc_stats->size_rtxs[code]) - / ggc_stats->total_size_rtxs)); - } - fprintf (stream, - "%-17s%10u%16ld%c\n", "Total", - ggc_stats->total_num_rtxs, - SCALE (ggc_stats->total_size_rtxs), - LABEL (ggc_stats->total_size_rtxs)); + ggc_pch_read (f, addr); - /* Don't gather statistics any more. */ - ggc_stats = NULL; + if (addr != mmi.preferred_base) + { + for (rt = gt_ggc_rtab; *rt; rt++) + for (rti = *rt; rti->base != NULL; rti++) + for (i = 0; i < rti->nelt; i++) + { + char **ptr = (char **)((char *)rti->base + rti->stride * i); + if (*ptr != NULL) + *ptr += (size_t)addr - (size_t)mmi.preferred_base; + } + + for (rt = gt_pch_cache_rtab; *rt; rt++) + for (rti = *rt; rti->base != NULL; rti++) + for (i = 0; i < rti->nelt; i++) + { + char **ptr = (char **)((char *)rti->base + rti->stride * i); + if (*ptr != NULL) + *ptr += (size_t)addr - (size_t)mmi.preferred_base; + } + + sorry ("had to relocate PCH"); + } + + gt_pch_restore_stringpool (); } diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c index 537f302..a150c5a 100644 --- a/gcc/ggc-page.c +++ b/gcc/ggc-page.c @@ -1,5 +1,5 @@ /* "Bag-of-pages" garbage collector for the GNU compiler. - Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GCC. @@ -147,6 +147,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA the indicated ORDER. */ #define OBJECTS_PER_PAGE(ORDER) objects_per_page_table[ORDER] +/* The number of objects in P. */ +#define OBJECTS_IN_PAGE(P) ((P)->bytes / OBJECT_SIZE ((P)->order)) + /* The size of an object on a page of the indicated ORDER. */ #define OBJECT_SIZE(ORDER) object_size_table[ORDER] @@ -202,6 +205,15 @@ struct max_alignment { #define MAX_ALIGNMENT (offsetof (struct max_alignment, u)) +/* Compute the smallest nonnegative number which when added to X gives + a multiple of F. */ + +#define ROUND_UP_VALUE(x, f) ((f) - 1 - ((f) - 1 + (x)) % (f)) + +/* Compute the smallest multiple of F that is >= X. */ + +#define ROUND_UP(x, f) (CEIL (x, f) * (f)) + /* The Ith entry is the number of objects on a page or order I. */ static unsigned objects_per_page_table[NUM_ORDERS]; @@ -1172,7 +1184,7 @@ init_ggc () /* If S is not a multiple of the MAX_ALIGNMENT, then round it up so that we're sure of getting aligned memory. */ - s = CEIL (s, MAX_ALIGNMENT) * MAX_ALIGNMENT; + s = ROUND_UP (s, MAX_ALIGNMENT); object_size_table[order] = s; } @@ -1225,7 +1237,7 @@ ggc_recalculate_in_use_p (p) /* Because the past-the-end bit in in_use_p is always set, we pretend there is one additional object. */ - num_objects = OBJECTS_PER_PAGE (p->order) + 1; + num_objects = OBJECTS_IN_PAGE (p) + 1; /* Reset the free object count. */ p->num_free_objects = num_objects; @@ -1294,12 +1306,13 @@ clear_marks () for (order = 2; order < NUM_ORDERS; order++) { - size_t num_objects = OBJECTS_PER_PAGE (order); - size_t bitmap_size = BITMAP_SIZE (num_objects + 1); page_entry *p; for (p = G.pages[order]; p != NULL; p = p->next) { + size_t num_objects = OBJECTS_IN_PAGE (p); + size_t bitmap_size = BITMAP_SIZE (num_objects + 1); + #ifdef ENABLE_CHECKING /* The data should be page-aligned. */ if ((size_t) p->page & (G.pagesize - 1)) @@ -1342,7 +1355,7 @@ sweep_pages () placed at the end of the list. */ page_entry * const last = G.page_tails[order]; - size_t num_objects = OBJECTS_PER_PAGE (order); + size_t num_objects; size_t live_objects; page_entry *p, *previous; int done; @@ -1358,6 +1371,8 @@ sweep_pages () /* Loop until all entries have been examined. */ done = (p == last); + + num_objects = OBJECTS_IN_PAGE (p); /* Add all live objects on this page to the count of allocated memory. */ @@ -1445,12 +1460,12 @@ poison_pages () for (order = 2; order < NUM_ORDERS; order++) { - size_t num_objects = OBJECTS_PER_PAGE (order); size_t size = OBJECT_SIZE (order); page_entry *p; for (p = G.pages[order]; p != NULL; p = p->next) { + size_t num_objects; size_t i; if (p->context_depth != G.context_depth) @@ -1460,6 +1475,7 @@ poison_pages () contexts. */ continue; + num_objects = OBJECTS_IN_PAGE (p); for (i = 0; i < num_objects; i++) { size_t word, bit; @@ -1581,11 +1597,11 @@ ggc_print_statistics () for (p = G.pages[i]; p; p = p->next) { allocated += p->bytes; - in_use += - (OBJECTS_PER_PAGE (i) - p->num_free_objects) * OBJECT_SIZE (i); + in_use += + (OBJECTS_IN_PAGE (p) - p->num_free_objects) * OBJECT_SIZE (i); overhead += (sizeof (page_entry) - sizeof (long) - + BITMAP_SIZE (OBJECTS_PER_PAGE (i) + 1)); + + BITMAP_SIZE (OBJECTS_IN_PAGE (p) + 1)); } fprintf (stderr, "%-5lu %10lu%c %10lu%c %10lu%c\n", (unsigned long) OBJECT_SIZE (i), @@ -1599,3 +1615,225 @@ ggc_print_statistics () SCALE (G.allocated), LABEL(G.allocated), SCALE (total_overhead), LABEL (total_overhead)); } + +struct ggc_pch_data +{ + struct ggc_pch_ondisk + { + unsigned totals[NUM_ORDERS]; + } d; + size_t base[NUM_ORDERS]; + size_t written[NUM_ORDERS]; +}; + +struct ggc_pch_data * +init_ggc_pch () +{ + return xcalloc (sizeof (struct ggc_pch_data), 1); +} + +void +ggc_pch_count_object (d, x, size) + struct ggc_pch_data *d; + void *x ATTRIBUTE_UNUSED; + size_t size; +{ + unsigned order; + + if (size <= 256) + order = size_lookup[size]; + else + { + order = 9; + while (size > OBJECT_SIZE (order)) + order++; + } + + d->d.totals[order]++; +} + +size_t +ggc_pch_total_size (d) + struct ggc_pch_data *d; +{ + size_t a = 0; + unsigned i; + + for (i = 0; i < NUM_ORDERS; i++) + a += ROUND_UP (d->d.totals[i] * OBJECT_SIZE (i), G.pagesize); + return a; +} + +void +ggc_pch_this_base (d, base) + struct ggc_pch_data *d; + void *base; +{ + size_t a = (size_t) base; + unsigned i; + + for (i = 0; i < NUM_ORDERS; i++) + { + d->base[i] = a; + a += ROUND_UP (d->d.totals[i] * OBJECT_SIZE (i), G.pagesize); + } +} + + +char * +ggc_pch_alloc_object (d, x, size) + struct ggc_pch_data *d; + void *x ATTRIBUTE_UNUSED; + size_t size; +{ + unsigned order; + char *result; + + if (size <= 256) + order = size_lookup[size]; + else + { + order = 9; + while (size > OBJECT_SIZE (order)) + order++; + } + + result = (char *) d->base[order]; + d->base[order] += OBJECT_SIZE (order); + return result; +} + +void +ggc_pch_prepare_write (d, f) + struct ggc_pch_data * d ATTRIBUTE_UNUSED; + FILE * f ATTRIBUTE_UNUSED; +{ + /* Nothing to do. */ +} + +void +ggc_pch_write_object (d, f, x, newx, size) + struct ggc_pch_data * d ATTRIBUTE_UNUSED; + FILE *f; + void *x; + void *newx ATTRIBUTE_UNUSED; + size_t size; +{ + unsigned order; + + if (size <= 256) + order = size_lookup[size]; + else + { + order = 9; + while (size > OBJECT_SIZE (order)) + order++; + } + + if (fwrite (x, size, 1, f) != 1) + fatal_io_error ("can't write PCH file"); + + /* In the current implementation, SIZE is always equal to + OBJECT_SIZE (order) and so the fseek is never executed. */ + if (size != OBJECT_SIZE (order) + && fseek (f, OBJECT_SIZE (order) - size, SEEK_CUR) != 0) + fatal_io_error ("can't write PCH file"); + + d->written[order]++; + if (d->written[order] == d->d.totals[order] + && fseek (f, ROUND_UP_VALUE (d->d.totals[order] * OBJECT_SIZE (order), + G.pagesize), + SEEK_CUR) != 0) + fatal_io_error ("can't write PCH file"); +} + +void +ggc_pch_finish (d, f) + struct ggc_pch_data * d; + FILE *f; +{ + if (fwrite (&d->d, sizeof (d->d), 1, f) != 1) + fatal_io_error ("can't write PCH file"); + free (d); +} + +void +ggc_pch_read (f, addr) + FILE *f; + void *addr; +{ + struct ggc_pch_ondisk d; + unsigned i; + char *offs = addr; + + /* We've just read in a PCH file. So, every object that used to be allocated + is now free. */ + clear_marks (); +#ifdef GGC_POISON + poison_pages (); +#endif + + /* No object read from a PCH file should ever be freed. So, set the + context depth to 1, and set the depth of all the currently-allocated + pages to be 1 too. PCH pages will have depth 0. */ + if (G.context_depth != 0) + abort (); + G.context_depth = 1; + for (i = 0; i < NUM_ORDERS; i++) + { + page_entry *p; + for (p = G.pages[i]; p != NULL; p = p->next) + p->context_depth = G.context_depth; + } + + /* Allocate the appropriate page-table entries for the pages read from + the PCH file. */ + if (fread (&d, sizeof (d), 1, f) != 1) + fatal_io_error ("can't read PCH file"); + + for (i = 0; i < NUM_ORDERS; i++) + { + struct page_entry *entry; + char *pte; + size_t bytes; + size_t num_objs; + size_t j; + + if (d.totals[i] == 0) + continue; + + bytes = ROUND_UP (d.totals[i] * OBJECT_SIZE (i), G.pagesize); + num_objs = bytes / OBJECT_SIZE (i); + entry = xcalloc (1, (sizeof (struct page_entry) + - sizeof (long) + + BITMAP_SIZE (num_objs + 1))); + entry->bytes = bytes; + entry->page = offs; + entry->context_depth = 0; + offs += bytes; + entry->num_free_objects = 0; + entry->order = i; + + for (j = 0; + j + HOST_BITS_PER_LONG <= num_objs + 1; + j += HOST_BITS_PER_LONG) + entry->in_use_p[j / HOST_BITS_PER_LONG] = -1; + for (; j < num_objs + 1; j++) + entry->in_use_p[j / HOST_BITS_PER_LONG] + |= 1L << (j % HOST_BITS_PER_LONG); + + for (pte = entry->page; + pte < entry->page + entry->bytes; + pte += G.pagesize) + set_page_table_entry (pte, entry); + + if (G.page_tails[i] != NULL) + G.page_tails[i]->next = entry; + else + G.pages[i] = entry; + G.page_tails[i] = entry; + } + + /* Update the statistics. */ + G.allocated = G.allocated_last_gc = offs - (char *)addr; +} diff --git a/gcc/ggc-simple.c b/gcc/ggc-simple.c index 554ef72..65bc1b6 100644 --- a/gcc/ggc-simple.c +++ b/gcc/ggc-simple.c @@ -1,5 +1,5 @@ /* Simple garbage collection for the GNU compiler. - Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GCC. @@ -28,6 +28,7 @@ #include "flags.h" #include "varray.h" #include "ggc.h" +#include "toplev.h" #include "timevar.h" #include "params.h" @@ -490,16 +491,90 @@ ggc_print_statistics () fprintf (stderr, "\n\ Total internal data (bytes)\t%ld%c\n\ -Number of leaves in tree\t%d\n\ +Number of leaves in tree\t%lu\n\ Average leaf depth\t\t%.1f\n", SCALE(G.objects * offsetof (struct ggc_mem, u)), LABEL(G.objects * offsetof (struct ggc_mem, u)), - nleaf, (double)sumdepth / (double)nleaf); + (unsigned long)nleaf, (double)sumdepth / (double)nleaf); /* Report overall memory usage. */ fprintf (stderr, "\n\ -Total objects allocated\t\t%d\n\ +Total objects allocated\t\t%ld\n\ Total memory in GC arena\t%ld%c\n", - G.objects, + (unsigned long)G.objects, SCALE(G.allocated), LABEL(G.allocated)); } + +struct ggc_pch_data * +init_ggc_pch () +{ + sorry ("Generating PCH files is not supported when using ggc-simple.c"); + /* It could be supported, but the code is not yet written. */ + return NULL; +} + +void +ggc_pch_count_object (d, x, size) + struct ggc_pch_data *d ATTRIBUTE_UNUSED; + void *x ATTRIBUTE_UNUSED; + size_t size ATTRIBUTE_UNUSED; +{ +} + +size_t +ggc_pch_total_size (d) + struct ggc_pch_data *d ATTRIBUTE_UNUSED; +{ + return 0; +} + +void +ggc_pch_this_base (d, base) + struct ggc_pch_data *d ATTRIBUTE_UNUSED; + void *base ATTRIBUTE_UNUSED; +{ +} + + +char * +ggc_pch_alloc_object (d, x, size) + struct ggc_pch_data *d ATTRIBUTE_UNUSED; + void *x ATTRIBUTE_UNUSED; + size_t size ATTRIBUTE_UNUSED; +{ + return NULL; +} + +void +ggc_pch_prepare_write (d, f) + struct ggc_pch_data * d ATTRIBUTE_UNUSED; + FILE * f ATTRIBUTE_UNUSED; +{ +} + +void +ggc_pch_write_object (d, f, x, newx, size) + struct ggc_pch_data * d ATTRIBUTE_UNUSED; + FILE *f ATTRIBUTE_UNUSED; + void *x ATTRIBUTE_UNUSED; + void *newx ATTRIBUTE_UNUSED; + size_t size ATTRIBUTE_UNUSED; +{ +} + +void +ggc_pch_finish (d, f) + struct ggc_pch_data * d ATTRIBUTE_UNUSED; + FILE *f ATTRIBUTE_UNUSED; +{ +} + +void +ggc_pch_read (f, addr) + FILE *f ATTRIBUTE_UNUSED; + void *addr ATTRIBUTE_UNUSED; +{ + /* This should be impossible, since we won't generate any valid PCH + files for this configuration. */ + abort (); +} diff --git a/gcc/ggc.h b/gcc/ggc.h index 4cd6242..86ae60a 100644 --- a/gcc/ggc.h +++ b/gcc/ggc.h @@ -18,9 +18,6 @@ along with GCC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "varray.h" -#include "gtype-desc.h" - /* Symbols are marked with `ggc' for `gcc gc' so as not to interfere with an external gc library that might be linked in. */ @@ -29,10 +26,39 @@ extern const char empty_string[]; /* empty string */ extern const char digit_vector[]; /* "0" .. "9" */ #define digit_string(d) (digit_vector + ((d) * 2)) -/* Manipulate global roots that are needed between calls to gc. - THIS ROUTINE IS OBSOLETE, do not use it for new code. */ -extern void ggc_add_root PARAMS ((void *base, int nelt, - int size, void (*)(void *))); +/* Internal functions and data structures used by the GTY + machinery. */ + +/* The first parameter is a pointer to a pointer, the second a cookie. */ +typedef void (*gt_pointer_operator) PARAMS ((void *, void *)); + +#include "gtype-desc.h" + +/* One of these applies its third parameter (with cookie in the fourth + parameter) to each pointer in the object pointed to by the first + parameter, using the second parameter. */ +typedef void (*gt_note_pointers) + PARAMS ((void *, void *, gt_pointer_operator, void *)); + +/* One of these is called before objects are re-ordered in memory. + The first parameter is the original object, the second is the + subobject that has had its pointers reordered, the third parameter + can compute the new values of a pointer when given the cookie in + the fourth parameter. */ +typedef void (*gt_handle_reorder) + PARAMS ((void *, void *, gt_pointer_operator, void *)); + +/* Used by the gt_pch_n_* routines. Register an object in the hash table. */ +extern int gt_pch_note_object + PARAMS ((void *, void *, gt_note_pointers)); + +/* Used by the gt_pch_n_* routines. Register that an object has a reorder + function. */ +extern void gt_pch_note_reorder + PARAMS ((void *, void *, gt_handle_reorder)); + +/* Mark the object in the first parameter and anything it points to. */ +typedef void (*gt_pointer_walker) PARAMS ((void *)); /* Structures for the easy way to mark roots. In an array, terminated by having base == NULL.*/ @@ -40,12 +66,15 @@ struct ggc_root_tab { void *base; size_t nelt; size_t stride; - void (*cb) PARAMS ((void *)); + gt_pointer_walker cb; + gt_pointer_walker pchw; }; -#define LAST_GGC_ROOT_TAB { NULL, 0, 0, NULL } +#define LAST_GGC_ROOT_TAB { NULL, 0, 0, NULL, NULL } /* Pointers to arrays of ggc_root_tab, terminated by NULL. */ extern const struct ggc_root_tab * const gt_ggc_rtab[]; extern const struct ggc_root_tab * const gt_ggc_deletable_rtab[]; +extern const struct ggc_root_tab * const gt_pch_cache_rtab[]; +extern const struct ggc_root_tab * const gt_pch_scalar_rtab[]; /* Structure for hash table cache marking. */ struct htab; @@ -53,23 +82,19 @@ struct ggc_cache_tab { struct htab * *base; size_t nelt; size_t stride; - void (*cb) PARAMS ((void *)); + gt_pointer_walker cb; + gt_pointer_walker pchw; int (*marked_p) PARAMS ((const void *)); }; -#define LAST_GGC_CACHE_TAB { NULL, 0, 0, NULL, NULL } +#define LAST_GGC_CACHE_TAB { NULL, 0, 0, NULL, NULL, NULL } /* Pointers to arrays of ggc_cache_tab, terminated by NULL. */ extern const struct ggc_cache_tab * const gt_ggc_cache_rtab[]; -extern void ggc_mark_roots PARAMS ((void)); - /* If EXPR is not NULL and previously unmarked, mark it and evaluate to true. Otherwise evaluate to false. */ #define ggc_test_and_set_mark(EXPR) \ ((EXPR) != NULL && ((void *) (EXPR)) != (void *) 1 && ! ggc_set_mark (EXPR)) -#define ggc_mark_rtx gt_ggc_m_7rtx_def -#define ggc_mark_tree gt_ggc_m_9tree_node - #define ggc_mark(EXPR) \ do { \ const void *const a__ = (EXPR); \ @@ -77,11 +102,45 @@ extern void ggc_mark_roots PARAMS ((void)); ggc_set_mark (a__); \ } while (0) -/* A GC implementation must provide these functions. */ +/* Actually set the mark on a particular region of memory, but don't + follow pointers. This function is called by ggc_mark_*. It + returns zero if the object was not previously marked; non-zero if + the object was already marked, or if, for any other reason, + pointers in this data structure should not be traversed. */ +extern int ggc_set_mark PARAMS ((const void *)); + +/* Return 1 if P has been marked, zero otherwise. + P must have been allocated by the GC allocator; it mustn't point to + static objects, stack variables, or memory allocated with malloc. */ +extern int ggc_marked_p PARAMS ((const void *)); + +/* Mark the entries in the string pool. */ +extern void ggc_mark_stringpool PARAMS ((void)); + +/* Call ggc_set_mark on all the roots. */ + +extern void ggc_mark_roots PARAMS ((void)); + +/* Save and restore the string pool entries for PCH. */ + +extern void gt_pch_save_stringpool PARAMS ((void)); +extern void gt_pch_restore_stringpool PARAMS ((void)); + +/* PCH and GGC handling for strings, mostly trivial. */ + +extern void gt_pch_p_S PARAMS ((void *, void *, + gt_pointer_operator, void *)); +extern void gt_pch_n_S PARAMS ((const void *)); +extern void gt_ggc_m_S PARAMS ((void *)); + +/* Initialise the string pool. */ +extern void init_stringpool PARAMS ((void)); + +/* A GC implementation must provide these functions. They are internal + to the GC system. */ /* Initialize the garbage collector. */ extern void init_ggc PARAMS ((void)); -extern void init_stringpool PARAMS ((void)); /* Start a new GGC context. Memory allocated in previous contexts will not be collected while the new context is active. */ @@ -91,6 +150,48 @@ extern void ggc_push_context PARAMS ((void)); will be merged with the old context. */ extern void ggc_pop_context PARAMS ((void)); +struct ggc_pch_data; + +/* Return a new ggc_pch_data structure. */ +extern struct ggc_pch_data *init_ggc_pch PARAMS ((void)); + +/* The second parameter and third parameters give the address and size + of an object. Update the ggc_pch_data structure with as much of + that information as is necessary. */ +extern void ggc_pch_count_object PARAMS ((struct ggc_pch_data *, + void *, size_t)); + +/* Return the total size of the data to be written to hold all + the objects previously passed to ggc_pch_count_object. */ +extern size_t ggc_pch_total_size PARAMS ((struct ggc_pch_data *)); + +/* The objects, when read, will most likely be at the address + in the second parameter. */ +extern void ggc_pch_this_base PARAMS ((struct ggc_pch_data *, + void *)); + +/* Assuming that the objects really do end up at the address + passed to ggc_pch_this_base, return the address of this object. */ +extern char *ggc_pch_alloc_object PARAMS ((struct ggc_pch_data *, + void *, size_t)); + +/* Write out any initial information required. */ +extern void ggc_pch_prepare_write PARAMS ((struct ggc_pch_data *, + FILE *)); +/* Write out this object, including any padding. */ +extern void ggc_pch_write_object PARAMS ((struct ggc_pch_data *, + FILE *, void *, void *, + size_t)); +/* All objects have been written, write out any final information + required. */ +extern void ggc_pch_finish PARAMS ((struct ggc_pch_data *, + FILE *)); + +/* A PCH file has just been read in at the address specified second + parameter. Set up the GC implementation for the new objects. */ +extern void ggc_pch_read PARAMS ((FILE *, void *)); + + /* Allocation. */ /* The internal primitive. */ @@ -115,6 +216,13 @@ extern void *ggc_calloc PARAMS ((size_t, size_t)); #define htab_create_ggc(SIZE, HASH, EQ, DEL) \ htab_create_alloc (SIZE, HASH, EQ, DEL, ggc_calloc, NULL) +#define splay_tree_new_ggc(COMPARE) \ + splay_tree_new_with_allocator (COMPARE, NULL, NULL, \ + &ggc_splay_alloc, &ggc_splay_dont_free, \ + NULL) +extern PTR ggc_splay_alloc PARAMS ((int, void *)); +extern void ggc_splay_dont_free PARAMS ((void *, void *)); + /* Allocate a gc-able string, and fill it with LENGTH bytes from CONTENTS. If LENGTH is -1, then CONTENTS is assumed to be a null-terminated string and the memory sized accordingly. */ @@ -128,47 +236,25 @@ extern const char *ggc_alloc_string PARAMS ((const char *contents, function is called, not during allocations. */ extern void ggc_collect PARAMS ((void)); -/* Actually set the mark on a particular region of memory, but don't - follow pointers. This function is called by ggc_mark_*. It - returns zero if the object was not previously marked; nonzero if - the object was already marked, or if, for any other reason, - pointers in this data structure should not be traversed. */ -extern int ggc_set_mark PARAMS ((const void *)); +/* Return the number of bytes allocated at the indicated address. */ +extern size_t ggc_get_size PARAMS ((const void *)); -/* Return 1 if P has been marked, zero otherwise. - P must have been allocated by the GC allocator; it mustn't point to - static objects, stack variables, or memory allocated with malloc. */ -extern int ggc_marked_p PARAMS ((const void *)); +/* Write out all GCed objects to F. */ +extern void gt_pch_save PARAMS ((FILE *f)); +/* Read objects previously saved with gt_pch_save from F. */ +extern void gt_pch_restore PARAMS ((FILE *f)); + /* Statistics. */ /* This structure contains the statistics common to all collectors. Particular collectors can extend this structure. */ typedef struct ggc_statistics { - /* The Ith element is the number of nodes allocated with code I. */ - unsigned num_trees[256]; - /* The Ith element is the number of bytes allocated by nodes with - code I. */ - size_t size_trees[256]; - /* The Ith element is the number of nodes allocated with code I. */ - unsigned num_rtxs[256]; - /* The Ith element is the number of bytes allocated by nodes with - code I. */ - size_t size_rtxs[256]; - /* The total size of the tree nodes allocated. */ - size_t total_size_trees; - /* The total size of the RTL nodes allocated. */ - size_t total_size_rtxs; - /* The total number of tree nodes allocated. */ - unsigned total_num_trees; - /* The total number of RTL nodes allocated. */ - unsigned total_num_rtxs; + /* At present, we don't really gather any interesting statistics. */ + int unused; } ggc_statistics; -/* Return the number of bytes allocated at the indicated address. */ -extern size_t ggc_get_size PARAMS ((const void *)); - /* Used by the various collectors to gather and print statistics that do not depend on the collector in use. */ extern void ggc_print_common_statistics PARAMS ((FILE *, ggc_statistics *)); diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index 34d39a4..00b5e50 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,77 @@ +2003-01-09 Geoffrey Keating + + Merge from pch-branch: + + 2002-12-02 Geoffrey Keating + + * Make-lang.in (java/gjavah.o): Update dependencies. + * gjavah.c: Include ggc.h. + + 2002-08-16 Geoffrey Keating + + * Make-lang.in (GCJH_OBJS): Add ggc-none.o. + (JCFDUMP_OBJS): Add ggc-none.o. + (java/jcf-dump.o): Depend on GGC_H. + * jcf-reader.c (jcf_parse_constant_pool): Use ggc_alloc to allocate + CPool substructures. + * jcf-parse.c (process_zip_dir): Use ggc_alloc to allocate JCFs. + * jcf-dump.c: Include ggc.h. + + 2002-08-08 Geoffrey Keating + + * jcf.h (union cpool_entry): New. + (struct CPool): Use gengtype to mark. Change field 'data' to be + an array of unions. + (struct JCF): Use gengtype to mark. + (CPOOL_UINT): Update for new cpool_entry type. + (CPOOL_USHORT1): Likewise. + (CPOOL_USHORT2): Likewise. + (CPOOL_FINISH): Use GC to free cpool subfields. + * parse.h (struct parser_ctxt): Mark field current_jcf. + * lex.c (java_init_lex): Use GC to allocate struct JCF. + * jcf-parse.c (HANDLE_CONSTANT_Utf8): Update for new cpool_entry type. + (main_jcf): Use gengtype to mark. + (ggc_mark_jcf): Delete. + (get_constant): Update for new cpool_entry type. + (give_name_to_class): Likewise. + (get_class_constant): Likewise. + (init_outgoing_cpool): Use GGC to allocate struct CPool. + (java_parse_file): Use GGC to allocate struct JCF. + (init_jcf_parse): Don't call ggc_add_root. + * jcf-reader.c (jcf_parse_constant_pool): Update for new + cpool_entry type. + * java-tree.h (current_jcf): Use gengtype to mark. + (CPOOL_UTF): Update for new cpool_entry type. + (outgoing_cpool): Use gengtype to mark. + (struct lang_type): GC struct JCF and struct CPool. + * config-lang.in (gtfiles): Add jcf.h. + * constants.c (find_tree_constant): New. + (set_constant_entry): Allocate cpool subfields using GGC. Update + for new cpool_entry type. + (find_constant1): Update for new cpool_entry type. + (find_constant2): Likewise. + (find_utf8_constant): Use find_tree_constant. + (find_class_or_string_constant): Remove unnecessary cast to jword. + Update for new cpool_entry type. + (count_constant_pool_bytes): Update for new cpool_entry type. + (write_constant_pool): Likewise. + (alloc_name_constant): Use find_tree_constant. + (build_constants_constructor): Update for new cpool_entry type. + + 2002-08-08 Geoffrey Keating + + * parse.y (mark_parser_ctxt): Delete. + (goal): Don't use ggc_add_root. + (create_new_parser_context): Use GC to allocate struct parser_ctxt. + (java_pop_parser_context): Let GC free parser_ctxt. + (java_parser_context_resume): Likewise. + * parse.h (struct parser_ctxt): Use gengtype to mark. + (ctxp): Likewise. + (ctxp_for_generation): Likewise. + * lex.h (struct java_lc_s): Mark for gengtype. + (java_lexer): Rearrange for gengtype. + * config-lang.in (gtfiles): Add lex.h, parse.h. + 2003-01-09 Kaveh R. Ghazi * All Files: Remove PARAMS macro. diff --git a/gcc/java/Make-lang.in b/gcc/java/Make-lang.in index b04a975..bd839d6 100644 --- a/gcc/java/Make-lang.in +++ b/gcc/java/Make-lang.in @@ -113,12 +113,12 @@ JAVA_OBJS = java/parse.o java/class.o java/decl.o java/expr.o \ java/jcf-path.o java/xref.o java/boehm.o java/java-tree-inline.o mkdeps.o GCJH_OBJS = java/gjavah.o java/jcf-io.o java/jcf-depend.o java/jcf-path.o \ - java/zextract.o version.o mkdeps.o errors.o + java/zextract.o version.o mkdeps.o errors.o ggc-none.o JVSCAN_OBJS = java/parse-scan.o java/jv-scan.o version.o JCFDUMP_OBJS = java/jcf-dump.o java/jcf-io.o java/jcf-depend.o java/jcf-path.o \ - java/zextract.o errors.o version.o mkdeps.o + java/zextract.o errors.o version.o mkdeps.o ggc-none.o JVGENMAIN_OBJS = java/jvgenmain.o java/mangle_name.o errors.o @@ -267,9 +267,9 @@ java/parse.o: java/parse.c java/jcf-reader.c $(CONFIG_H) $(SYSTEM_H) \ java/lex.h $(GGC_H) debug.h gt-java-parse.h gtype-java.h java/jcf-dump.o: $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(JAVA_TREE_H) \ java/jcf-dump.c java/jcf-reader.c java/jcf.h java/javaop.h java/javaop.def \ - version.h + version.h $(GGC_H) java/gjavah.o: $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(JAVA_TREE_H) \ - java/gjavah.c java/jcf-reader.c java/jcf.h java/javaop.h version.h + java/gjavah.c java/jcf-reader.c java/jcf.h java/javaop.h version.h $(GGC_H) java/boehm.o: java/boehm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) $(JAVA_TREE_H) java/parse.h toplev.h java/buffer.o: java/buffer.c $(CONFIG_H) java/buffer.h $(SYSTEM_H) coretypes.h \ diff --git a/gcc/java/config-lang.in b/gcc/java/config-lang.in index 993763e..05a6fdf 100644 --- a/gcc/java/config-lang.in +++ b/gcc/java/config-lang.in @@ -36,7 +36,7 @@ compilers="jc1\$(exeext) jvgenmain\$(exeext)" stagestuff="jc1\$(exeext) gcj\$(exeext) jvgenmain\$(exeext) gcjh\$(exeext) jv-scan\$(exeext) jcf-dump\$(exeext)" -gtfiles="\$(srcdir)/java/java-tree.h \$(srcdir)/java/builtins.c \$(srcdir)/java/class.c \$(srcdir)/java/constants.c \$(srcdir)/java/decl.c \$(srcdir)/java/expr.c \$(srcdir)/java/jcf-parse.c \$(srcdir)/java/jcf-write.c \$(srcdir)/java/lang.c \$(srcdir)/java/mangle.c \$(srcdir)/java/parse.y" +gtfiles="\$(srcdir)/java/java-tree.h \$(srcdir)/java/jcf.h \$(srcdir)/java/lex.h \$(srcdir)/java/parse.h \$(srcdir)/java/builtins.c \$(srcdir)/java/class.c \$(srcdir)/java/constants.c \$(srcdir)/java/decl.c \$(srcdir)/java/expr.c \$(srcdir)/java/jcf-parse.c \$(srcdir)/java/jcf-write.c \$(srcdir)/java/lang.c \$(srcdir)/java/mangle.c \$(srcdir)/java/parse.y" target_libs=${libgcj_saved} lang_dirs="zlib fastjar" diff --git a/gcc/java/constants.c b/gcc/java/constants.c index 11efc2b..a187238 100644 --- a/gcc/java/constants.c +++ b/gcc/java/constants.c @@ -32,6 +32,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "ggc.h" static void set_constant_entry (CPool *, int, int, jword); +static int find_tree_constant (CPool *, int, tree); static int find_class_or_string_constant (CPool *, int, tree); static int find_name_and_type_constant (CPool *, tree, tree); static tree get_tag_node (int); @@ -49,8 +50,8 @@ set_constant_entry (cpool, index, tag, value) if (cpool->data == NULL) { cpool->capacity = 100; - cpool->tags = xmalloc (sizeof(uint8) * cpool->capacity); - cpool->data = xmalloc (sizeof(jword) * cpool->capacity); + cpool->tags = ggc_alloc (sizeof(uint8) * cpool->capacity); + cpool->data = ggc_alloc (sizeof(union cpool_entry) * cpool->capacity); cpool->count = 1; } if (index >= cpool->capacity) @@ -58,13 +59,15 @@ set_constant_entry (cpool, index, tag, value) cpool->capacity *= 2; if (index >= cpool->capacity) cpool->capacity = index + 10; - cpool->tags = xrealloc (cpool->tags, sizeof(uint8) * cpool->capacity); - cpool->data = xrealloc (cpool->data, sizeof(jword) * cpool->capacity); + cpool->tags = ggc_realloc (cpool->tags, + sizeof(uint8) * cpool->capacity); + cpool->data = ggc_realloc (cpool->data, + sizeof(union cpool_entry) * cpool->capacity); } if (index >= cpool->count) cpool->count = index + 1; cpool->tags[index] = tag; - cpool->data[index] = value; + cpool->data[index].w = value; } /* Find (or create) a constant pool entry matching TAG and VALUE. */ @@ -78,7 +81,7 @@ find_constant1 (cpool, tag, value) int i; for (i = cpool->count; --i > 0; ) { - if (cpool->tags[i] == tag && cpool->data[i] == value) + if (cpool->tags[i] == tag && cpool->data[i].w == value) return i; } i = cpool->count == 0 ? 1 : cpool->count; @@ -98,8 +101,8 @@ find_constant2 (cpool, tag, word1, word2) for (i = cpool->count - 1; --i > 0; ) { if (cpool->tags[i] == tag - && cpool->data[i] == word1 - && cpool->data[i+1] == word2) + && cpool->data[i].w == word1 + && cpool->data[i+1].w == word2) return i; } i = cpool->count == 0 ? 1 : cpool->count; @@ -108,6 +111,25 @@ find_constant2 (cpool, tag, word1, word2) return i; } +static int +find_tree_constant (cpool, tag, value) + CPool *cpool; + int tag; + tree value; +{ + int i; + for (i = cpool->count; --i > 0; ) + { + if (cpool->tags[i] == tag && cpool->data[i].t == value) + return i; + } + i = cpool->count == 0 ? 1 : cpool->count; + set_constant_entry (cpool, i, tag, 0); + cpool->data[i].t = value; + return i; +} + + int find_utf8_constant (cpool, name) CPool *cpool; @@ -115,7 +137,7 @@ find_utf8_constant (cpool, name) { if (name == NULL_TREE) return 0; - return find_constant1 (cpool, CONSTANT_Utf8, (jword) name); + return find_tree_constant (cpool, CONSTANT_Utf8, name); } static int @@ -124,15 +146,15 @@ find_class_or_string_constant (cpool, tag, name) int tag; tree name; { - int j = find_utf8_constant (cpool, name); + jword j = find_utf8_constant (cpool, name); int i; for (i = cpool->count; --i > 0; ) { - if (cpool->tags[i] == tag && cpool->data[i] == (jword) j) + if (cpool->tags[i] == tag && cpool->data[i].w == j) return i; } i = cpool->count; - set_constant_entry (cpool, i, tag, (jword) j); + set_constant_entry (cpool, i, tag, j); return i; } @@ -255,7 +277,7 @@ count_constant_pool_bytes (cpool) break; case CONSTANT_Utf8: { - tree t = (tree) cpool->data[i]; + tree t = cpool->data[i].t; int len = IDENTIFIER_LENGTH (t); size += len + 2; } @@ -279,7 +301,7 @@ write_constant_pool (cpool, buffer, length) { unsigned char *ptr = buffer; int i = 1; - jword *datap = &cpool->data[1]; + union cpool_entry *datap = &cpool->data[1]; PUT2 (cpool->count); for ( ; i < cpool->count; i++, datap++) { @@ -293,23 +315,23 @@ write_constant_pool (cpool, buffer, length) case CONSTANT_InterfaceMethodref: case CONSTANT_Float: case CONSTANT_Integer: - PUT4 (*datap); + PUT4 (datap->w); break; case CONSTANT_Class: case CONSTANT_String: - PUT2 (*datap); + PUT2 (datap->w); break; break; case CONSTANT_Long: case CONSTANT_Double: - PUT4(*datap); + PUT4(datap->w); i++; datap++; - PUT4 (*datap); + PUT4 (datap->w); break; case CONSTANT_Utf8: { - tree t = (tree) *datap; + tree t = datap->t; int len = IDENTIFIER_LENGTH (t); PUT2 (len); PUTN (IDENTIFIER_POINTER (t), len); @@ -347,7 +369,7 @@ alloc_name_constant (tag, name) int tag; tree name; { - return find_constant1 (outgoing_cpool, tag, (jword) name); + return find_tree_constant (outgoing_cpool, tag, name); } /* Build an identifier for the internal name of reference type TYPE. */ @@ -438,7 +460,7 @@ build_constants_constructor () = tree_cons (NULL_TREE, get_tag_node (outgoing_cpool->tags[i]), tags_list); data_list - = tree_cons (NULL_TREE, build_utf8_ref ((tree)outgoing_cpool->data[i]), + = tree_cons (NULL_TREE, build_utf8_ref (outgoing_cpool->data[i].t), data_list); } if (outgoing_cpool->count > 0) diff --git a/gcc/java/gjavah.c b/gcc/java/gjavah.c index 4550997..0c33313 100644 --- a/gcc/java/gjavah.c +++ b/gcc/java/gjavah.c @@ -38,6 +38,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "javaop.h" #include "java-tree.h" #include "java-opcodes.h" +#include "ggc.h" #include "hashtab.h" #include diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h index b4ed394..9a79f3e 100644 --- a/gcc/java/java-tree.h +++ b/gcc/java/java-tree.h @@ -229,7 +229,7 @@ extern int flag_store_check; extern const char *current_encoding; /* The Java .class file that provides main_class; the main input file. */ -extern struct JCF *current_jcf; +extern GTY(()) struct JCF * current_jcf; typedef struct CPool constant_pool; @@ -241,7 +241,7 @@ typedef struct CPool constant_pool; /* The cpool->data[i] for a ResolvedClass points to a RECORD_TYPE. */ #define CONSTANT_ResolvedClass (CONSTANT_Class+CONSTANT_ResolvedFlag) -#define CPOOL_UTF(CPOOL, INDEX) ((tree) (CPOOL)->data[INDEX]) +#define CPOOL_UTF(CPOOL, INDEX) ((CPOOL)->data[INDEX].t) /* A NameAndType constant is represented as a TREE_LIST. The type is the signature string (as an IDENTIFIER_NODE). */ @@ -686,7 +686,7 @@ extern GTY(()) tree java_global_trees[JTI_MAX]; #define nativecode_ptr_type_node ptr_type_node /* They need to be reset before processing each class */ -extern struct CPool *outgoing_cpool; +extern GTY(()) struct CPool *outgoing_cpool; #define wfl_operator \ java_global_trees[JTI_WFL_OPERATOR] @@ -1066,8 +1066,8 @@ struct lang_decl GTY(()) struct lang_type GTY(()) { tree signature; - struct JCF * GTY ((skip (""))) jcf; - struct CPool * GTY ((skip (""))) cpool; + struct JCF * jcf; + struct CPool * cpool; tree cpool_data_ref; /* Cached */ tree finit_stmt_list; /* List of statements finit$ will use */ tree clinit_stmt_list; /* List of statements will use */ diff --git a/gcc/java/jcf-dump.c b/gcc/java/jcf-dump.c index e780b84..a5de5c5 100644 --- a/gcc/java/jcf-dump.c +++ b/gcc/java/jcf-dump.c @@ -53,6 +53,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "system.h" #include "coretypes.h" #include "tm.h" +#include "ggc.h" #include "jcf.h" #include "tree.h" diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c index 9379826..cd2c1cf 100644 --- a/gcc/java/jcf-parse.c +++ b/gcc/java/jcf-parse.c @@ -62,7 +62,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ text = (JCF)->read_ptr; \ save = text[LENGTH]; \ text[LENGTH] = 0; \ - (JCF)->cpool.data[INDEX] = (jword) get_identifier (text); \ + (JCF)->cpool.data[INDEX].t = get_identifier (text); \ text[LENGTH] = save; \ JCF_SKIP (JCF, LENGTH); } while (0) @@ -86,7 +86,7 @@ static GTY(()) tree parse_roots[3]; #define current_file_list parse_roots[2] /* The Java archive that provides main_class; the main input file. */ -static struct JCF main_jcf[1]; +static GTY(()) struct JCF * main_jcf; static struct ZipFile *localToFile; @@ -100,33 +100,9 @@ static void parse_source_file_2 (void); static void parse_source_file_3 (void); static void parse_class_file (void); static void set_source_filename (JCF *, int); -static void ggc_mark_jcf (void**); static void jcf_parse (struct JCF*); static void load_inner_classes (tree); -/* Mark (for garbage collection) all the tree nodes that are - referenced from JCF's constant pool table. Do that only if the JCF - hasn't been marked finished. */ - -static void -ggc_mark_jcf (elt) - void **elt; -{ - JCF *jcf = *(JCF**) elt; - if (jcf != NULL && !jcf->finished) - { - CPool *cpool = &jcf->cpool; - int size = CPOOL_COUNT(cpool); - int index; - for (index = 1; index < size; index++) - { - int tag = JPOOL_TAG (jcf, index); - if ((tag & CONSTANT_ResolvedFlag) || tag == CONSTANT_Utf8) - ggc_mark_tree ((tree) cpool->data[index]); - } - } -} - /* Handle "SourceFile" attribute. */ static void @@ -270,7 +246,7 @@ get_constant (jcf, index) goto bad; tag = JPOOL_TAG (jcf, index); if ((tag & CONSTANT_ResolvedFlag) || tag == CONSTANT_Utf8) - return (tree) jcf->cpool.data[index]; + return jcf->cpool.data[index].t; switch (tag) { case CONSTANT_Integer: @@ -352,7 +328,7 @@ get_constant (jcf, index) goto bad; } JPOOL_TAG (jcf, index) = tag | CONSTANT_ResolvedFlag; - jcf->cpool.data [index] = (jword) value; + jcf->cpool.data[index].t = value; return value; bad: internal_error ("bad value constant type %d, index %d", @@ -435,7 +411,7 @@ give_name_to_class (jcf, i) if (main_input_filename == NULL && jcf == main_jcf) main_input_filename = input_filename; - jcf->cpool.data[i] = (jword) this_class; + jcf->cpool.data[i].t = this_class; JPOOL_TAG (jcf, i) = CONSTANT_ResolvedClass; return this_class; } @@ -465,11 +441,11 @@ get_class_constant (JCF *jcf , int i) tree cname = unmangle_classname (name, nlength); type = lookup_class (cname); } - jcf->cpool.data[i] = (jword) type; + jcf->cpool.data[i].t = type; JPOOL_TAG (jcf, i) = CONSTANT_ResolvedClass; } else - type = (tree) jcf->cpool.data[i]; + type = jcf->cpool.data[i].t; return type; } @@ -709,8 +685,7 @@ load_inner_classes (cur_class) void init_outgoing_cpool () { - outgoing_cpool = xmalloc (sizeof (struct CPool)); - memset (outgoing_cpool, 0, sizeof (struct CPool)); + outgoing_cpool = ggc_alloc_cleared (sizeof (struct CPool)); } static void @@ -1074,7 +1049,7 @@ java_parse_file (set_yydebug) if (magic == 0xcafebabe) { CLASS_FILE_P (node) = 1; - current_jcf = ALLOC (sizeof (JCF)); + current_jcf = ggc_alloc (sizeof (JCF)); JCF_ZERO (current_jcf); current_jcf->read_state = finput; current_jcf->filbuf = jcf_filbuf_from_stdio; @@ -1086,6 +1061,7 @@ java_parse_file (set_yydebug) else if (magic == (JCF_u4)ZIPMAGIC) { ZIP_FILE_P (node) = 1; + main_jcf = ggc_alloc (sizeof (JCF)); JCF_ZERO (main_jcf); main_jcf->read_state = finput; main_jcf->filbuf = jcf_filbuf_from_stdio; @@ -1223,7 +1199,7 @@ process_zip_dir (FILE *finput) class_name = ALLOC (zdir->filename_length+1-6); file_name = ALLOC (zdir->filename_length+1); - jcf = ALLOC (sizeof (JCF)); + jcf = ggc_alloc (sizeof (JCF)); JCF_ZERO (jcf); strncpy (class_name, class_name_in_zip_dir, zdir->filename_length-6); @@ -1255,9 +1231,6 @@ process_zip_dir (FILE *finput) void init_jcf_parse () { - /* Register roots with the garbage collector. */ - ggc_add_root (¤t_jcf, 1, sizeof (JCF), (void (*)(void *))ggc_mark_jcf); - init_src_parse (); } diff --git a/gcc/java/jcf-reader.c b/gcc/java/jcf-reader.c index 1bd5299..da45cc9 100644 --- a/gcc/java/jcf-reader.c +++ b/gcc/java/jcf-reader.c @@ -264,8 +264,8 @@ jcf_parse_constant_pool (JCF* jcf) { int i, n; JPOOL_SIZE (jcf) = (JCF_FILL (jcf, 2), JCF_readu2 (jcf)); - jcf->cpool.tags = ALLOC (JPOOL_SIZE (jcf)); - jcf->cpool.data = ALLOC (sizeof (jword) * JPOOL_SIZE (jcf)); + jcf->cpool.tags = ggc_alloc (JPOOL_SIZE (jcf)); + jcf->cpool.data = ggc_alloc (sizeof (jword) * JPOOL_SIZE (jcf)); jcf->cpool.tags[0] = 0; #ifdef HANDLE_START_CONSTANT_POOL HANDLE_START_CONSTANT_POOL (JPOOL_SIZE (jcf)); @@ -285,25 +285,25 @@ jcf_parse_constant_pool (JCF* jcf) { case CONSTANT_String: case CONSTANT_Class: - jcf->cpool.data[i] = JCF_readu2 (jcf); + jcf->cpool.data[i].w = JCF_readu2 (jcf); break; case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: case CONSTANT_NameAndType: - jcf->cpool.data[i] = JCF_readu2 (jcf); - jcf->cpool.data[i] |= JCF_readu2 (jcf) << 16; + jcf->cpool.data[i].w = JCF_readu2 (jcf); + jcf->cpool.data[i].w |= JCF_readu2 (jcf) << 16; break; case CONSTANT_Integer: case CONSTANT_Float: - jcf->cpool.data[i] = JCF_readu4 (jcf); + jcf->cpool.data[i].w = JCF_readu4 (jcf); break; case CONSTANT_Long: case CONSTANT_Double: - jcf->cpool.data[i] = JCF_readu4 (jcf); + jcf->cpool.data[i].w = JCF_readu4 (jcf); i++; /* These take up two spots in the constant pool */ jcf->cpool.tags[i] = 0; - jcf->cpool.data[i] = JCF_readu4 (jcf); + jcf->cpool.data[i].w = JCF_readu4 (jcf); break; case CONSTANT_Utf8: n = JCF_readu2 (jcf); @@ -311,7 +311,7 @@ jcf_parse_constant_pool (JCF* jcf) #ifdef HANDLE_CONSTANT_Utf8 HANDLE_CONSTANT_Utf8(jcf, i, n); #else - jcf->cpool.data[i] = JCF_TELL(jcf) - 2; + jcf->cpool.data[i].w = JCF_TELL(jcf) - 2; JCF_SKIP (jcf, n); #endif break; diff --git a/gcc/java/jcf.h b/gcc/java/jcf.h index 0555f36..c8e6aa7 100644 --- a/gcc/java/jcf.h +++ b/gcc/java/jcf.h @@ -55,9 +55,17 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #endif struct JCF; -typedef int (*jcf_filbuf_t) (struct JCF*, int needed); +typedef int (*jcf_filbuf_t) PARAMS ((struct JCF*, int needed)); -typedef struct CPool { +union cpool_entry GTY(()) { + jword GTY ((tag ("0"))) w; + tree GTY ((tag ("1"))) t; +}; + +#define cpool_entry_is_tree(tag) \ + (tag & CONSTANT_ResolvedFlag) || tag == CONSTANT_Utf8 + +typedef struct CPool GTY(()) { /* Available number of elements in the constants array, before it must be re-allocated. */ int capacity; @@ -65,29 +73,33 @@ typedef struct CPool { /* The constant_pool_count. */ int count; - uint8* tags; + uint8* GTY((length ("%h.count"))) tags; - jword* data; + union cpool_entry * GTY((length ("%h.count"), + desc ("cpool_entry_is_tree (%1.tags%a)"))) data; } CPool; struct ZipDirectory; /* JCF encapsulates the state of reading a Java Class File. */ -typedef struct JCF { - unsigned char *buffer; - unsigned char *buffer_end; - unsigned char *read_ptr; - unsigned char *read_end; +typedef struct JCF GTY(()) { + unsigned char * GTY ((skip (""))) buffer; + unsigned char * GTY ((skip (""))) buffer_end; + unsigned char * GTY ((skip (""))) read_ptr; + unsigned char * GTY ((skip (""))) read_end; int java_source : 1; int right_zip : 1; int finished : 1; jcf_filbuf_t filbuf; - void *read_state; + PTR GTY ((skip (""))) read_state; const char *filename; const char *classname; - struct ZipDirectory *zipd; /* Directory entry where it was found */ - JCF_u2 access_flags, this_class, super_class; + /* Directory entry where it was found. */ + struct ZipDirectory * GTY ((skip (""))) zipd; + JCF_u2 access_flags; + JCF_u2 this_class; + JCF_u2 super_class; CPool cpool; } JCF; /*typedef JCF* JCF_FILE;*/ @@ -102,13 +114,13 @@ typedef struct JCF { #define JPOOL_SIZE(JCF) CPOOL_COUNT(&(JCF)->cpool) #define JPOOL_TAG(JCF, INDEX) ((JCF)->cpool.tags[INDEX]) /* The INDEX'th constant pool entry as a JCF_u4. */ -#define CPOOL_UINT(CPOOL, INDEX) ((CPOOL)->data[INDEX]) +#define CPOOL_UINT(CPOOL, INDEX) ((CPOOL)->data[INDEX].w) #define JPOOL_UINT(JCF, INDEX) CPOOL_UINT(&(JCF)->cpool, INDEX) /*deprecated*/ /* The first uint16 of the INDEX'th constant pool entry. */ -#define CPOOL_USHORT1(CPOOL, INDEX) ((CPOOL)->data[INDEX] & 0xFFFF) +#define CPOOL_USHORT1(CPOOL, INDEX) ((CPOOL)->data[INDEX].w & 0xFFFF) #define JPOOL_USHORT1(JCF, INDEX) CPOOL_USHORT1(&(JCF)->cpool, INDEX) /* The second uint16 of the INDEX'th constant pool entry. */ -#define CPOOL_USHORT2(CPOOL, INDEX) ((CPOOL)->data[INDEX] >> 16) +#define CPOOL_USHORT2(CPOOL, INDEX) ((CPOOL)->data[INDEX].w >> 16) #define JPOOL_USHORT2(JCF, INDEX) CPOOL_USHORT2(&(JCF)->cpool, INDEX) #define JPOOL_LONG(JCF, INDEX) \ WORDS_TO_LONG (JPOOL_UINT(JCF, INDEX), JPOOL_UINT(JCF, (INDEX)+1)) @@ -128,9 +140,10 @@ typedef struct JCF { #define CPOOL_INDEX_IN_RANGE(CPOOL, INDEX) \ ((INDEX) > 0 && (INDEX) < CPOOL_COUNT(CPOOL)) -#define CPOOL_FINISH(CPOOL) { \ - if ((CPOOL)->tags) FREE ((CPOOL)->tags); \ - if ((CPOOL)->data) FREE ((CPOOL)->data); } +#define CPOOL_FINISH(CPOOL) { \ + (CPOOL)->tags = 0; \ + (CPOOL)->data = 0; \ + } #define JCF_FINISH(JCF) { \ CPOOL_FINISH(&(JCF)->cpool); \ diff --git a/gcc/java/lex.c b/gcc/java/lex.c index c6744f4..976d0cf 100644 --- a/gcc/java/lex.c +++ b/gcc/java/lex.c @@ -125,7 +125,7 @@ java_init_lex (finput, encoding) CPC_INSTANCE_INITIALIZER_LIST (ctxp) = NULL_TREE; memset (ctxp->modifier_ctx, 0, sizeof (ctxp->modifier_ctx)); - memset (current_jcf, 0, sizeof (JCF)); + current_jcf = ggc_alloc_cleared (sizeof (JCF)); ctxp->current_parsed_class = NULL; ctxp->package = NULL_TREE; #endif diff --git a/gcc/java/lex.h b/gcc/java/lex.h index 9579036..aa9a2be 100644 --- a/gcc/java/lex.h +++ b/gcc/java/lex.h @@ -96,13 +96,13 @@ struct java_error { int error; }; -typedef struct _java_lc { +typedef struct java_lc_s GTY(()) { int line; int prev_col; int col; } java_lc; -typedef struct java_lexer +struct java_lexer { /* The file from which we're reading. */ FILE *finput; @@ -155,7 +155,8 @@ typedef struct java_lexer int out_last; #endif /* HAVE_ICONV */ -} java_lexer; +}; +typedef struct java_lexer java_lexer; /* Destroy a lexer object. */ extern void java_destroy_lexer (java_lexer *); diff --git a/gcc/java/parse.h b/gcc/java/parse.h index 37731fb..a6681af 100644 --- a/gcc/java/parse.h +++ b/gcc/java/parse.h @@ -427,9 +427,6 @@ enum { INVOKE_VIRTUAL }; -/* We need the resolution stuff only if we compile jc1 */ -#ifndef JC1_LITE - /* Unresolved type identifiers handling. When we process the source code, we blindly accept an unknown type identifier and try to resolve it later. When an unknown type identifier is encountered @@ -509,13 +506,12 @@ typedef struct _jdep { #define JDEP_RESOLVED_P(J) \ (!(J)->solv || TREE_CODE ((J)->solv) != POINTER_TYPE) -typedef struct _jdeplist { +struct jdeplist_s { jdep *first; jdep *last; - struct _jdeplist *next; -} jdeplist; - -#endif /* JC1_LITE */ + struct jdeplist_s *next; +}; +typedef struct jdeplist_s jdeplist; #define CLASSD_FIRST(CD) ((CD)->first) #define CLASSD_LAST(CD) ((CD)->last) @@ -727,14 +723,15 @@ typedef struct _jdeplist { #define DECL_INHERITED_SOURCE_LINE(DECL) (DECL_CHECK (DECL)->decl.u2.i) /* Parser context data structure. */ -struct parser_ctxt { +struct parser_ctxt GTY(()) { const char *filename; /* Current filename */ struct parser_ctxt *next; - java_lexer *lexer; /* Current lexer state */ + java_lexer * GTY((skip (""))) lexer; /* Current lexer state */ char marker_begining; /* Marker. Should be a sub-struct */ - struct java_line *p_line, *c_line; /* Previous and current line */ + struct java_line * GTY ((skip (""))) p_line; /* Previous line */ + struct java_line * GTY ((skip (""))) c_line; /* Current line */ java_lc elc; /* Error's line column info */ int ccb_indent; /* Keep track of {} indent, lexer */ int first_ccb_indent1; /* First { at ident level 1 */ @@ -742,7 +739,7 @@ struct parser_ctxt { int parser_ccb_indent; /* Keep track of {} indent, parser */ int osb_depth; /* Current depth of [ in an expression */ int osb_limit; /* Limit of this depth */ - int *osb_number; /* Keep track of ['s */ + int * GTY ((skip (""))) osb_number; /* Keep track of ['s */ int lineno; /* Current lineno */ char marker_end; /* End marker. Should be a sub-struct */ @@ -761,13 +758,12 @@ struct parser_ctxt { /* Flag to report certain errors (fix this documentation. FIXME) */ unsigned class_err:1; - /* This section is defined only if we compile jc1 */ -#ifndef JC1_LITE + /* This section is used only if we compile jc1 */ tree modifier_ctx [12]; /* WFL of modifiers */ tree class_type; /* Current class */ tree function_decl; /* Current function decl, save/restore */ - struct JCF *current_jcf; /* CU jcf */ + struct JCF * current_jcf; /* CU jcf */ int prevent_ese; /* Prevent expression statement error */ @@ -778,7 +774,7 @@ struct parser_ctxt { /* These two lists won't survive file traversal */ tree class_list; /* List of classes in a CU */ - jdeplist *classd_list; /* Classe dependencies in a CU */ + jdeplist * GTY((skip (""))) classd_list; /* Classe dependencies in a CU */ tree current_parsed_class; /* Class currently parsed */ tree current_parsed_class_un; /* Curr. parsed class unqualified name */ @@ -801,7 +797,6 @@ struct parser_ctxt { constructor. This flag is used to trap illegal argument usage during an explicit constructor invocation. */ -#endif /* JC1_LITE */ }; /* A set of macros to push/pop/access the currently parsed class. */ @@ -947,7 +942,7 @@ ATTRIBUTE_NORETURN ; extern void java_expand_classes (void); -extern struct parser_ctxt *ctxp; -extern struct parser_ctxt *ctxp_for_generation; +extern GTY(()) struct parser_ctxt *ctxp; +extern GTY(()) struct parser_ctxt *ctxp_for_generation; #endif /* ! GCC_JAVA_PARSE_H */ diff --git a/gcc/java/parse.y b/gcc/java/parse.y index 3dbe3b3..c67a42e 100644 --- a/gcc/java/parse.y +++ b/gcc/java/parse.y @@ -304,13 +304,16 @@ static tree maybe_build_thisn_access_method (tree); static tree build_outer_field_access (tree, tree); static tree build_outer_field_access_methods (tree); -static tree build_outer_field_access_expr (int, tree, tree, tree, tree); +static tree build_outer_field_access_expr (int, tree, tree, + tree, tree); static tree build_outer_method_access_method (tree); static tree build_new_access_id (void); -static tree build_outer_field_access_method (tree, tree, tree, tree, tree); +static tree build_outer_field_access_method (tree, tree, tree, + tree, tree); static int outer_field_access_p (tree, tree); -static int outer_field_expanded_access_p (tree, tree *, tree *, tree *); +static int outer_field_expanded_access_p (tree, tree *, + tree *, tree *); static tree outer_field_access_fix (tree, tree, tree); static tree build_incomplete_class_ref (int, tree); static tree patch_incomplete_class_ref (tree); @@ -321,7 +324,6 @@ static void add_inner_class_fields (tree, tree); static tree build_dot_class_method (tree); static tree build_dot_class_method_invocation (tree); static void create_new_parser_context (int); -static void mark_parser_ctxt (void *); static tree maybe_build_class_init_for_field (tree, tree); static int attach_init_test_initialization_flags (PTR *, PTR); @@ -594,18 +596,7 @@ static GTY(()) tree src_parse_roots[1]; %% /* 19.2 Production from 2.3: The Syntactic Grammar */ -goal: - { - /* Register static variables with the garbage - collector. */ - ggc_add_root (&ctxp, 1, - sizeof (struct parser_ctxt *), - mark_parser_ctxt); - ggc_add_root (&ctxp_for_generation, 1, - sizeof (struct parser_ctxt *), - mark_parser_ctxt); - } - compilation_unit +goal: compilation_unit {} ; @@ -2669,7 +2660,7 @@ create_new_parser_context (copy_from_previous) { struct parser_ctxt *new; - new = (struct parser_ctxt *)xmalloc(sizeof (struct parser_ctxt)); + new = (struct parser_ctxt *) ggc_alloc (sizeof (struct parser_ctxt)); if (copy_from_previous) { memcpy ((PTR)new, (PTR)ctxp, sizeof (struct parser_ctxt)); @@ -2730,8 +2721,6 @@ java_pop_parser_context (generate) toFree->next = ctxp_for_generation; ctxp_for_generation = toFree; } - else - free (toFree); } /* Create a parser context for the use of saving some global @@ -2830,10 +2819,6 @@ java_parser_context_resume () /* Re-installed the data for the parsing to carry on */ memcpy (&ctxp->marker_begining, &old->marker_begining, (size_t)(&ctxp->marker_end - &ctxp->marker_begining)); - - /* Buffer context can now be discarded */ - free (saver); - free (old); } /* Add a new anchor node to which all statement(s) initializing static @@ -6732,10 +6717,9 @@ process_imports () tree to_be_found = EXPR_WFL_NODE (TREE_PURPOSE (import)); char *original_name; - obstack_grow0 (&temporary_obstack, - IDENTIFIER_POINTER (to_be_found), - IDENTIFIER_LENGTH (to_be_found)); - original_name = obstack_finish (&temporary_obstack); + original_name = xmemdup (IDENTIFIER_POINTER (to_be_found), + IDENTIFIER_LENGTH (to_be_found), + IDENTIFIER_LENGTH (to_be_found) + 1); /* Don't load twice something already defined. */ if (IDENTIFIER_CLASS_VALUE (to_be_found)) @@ -6771,7 +6755,7 @@ process_imports () error_found = 1; } - obstack_free (&temporary_obstack, original_name); + free (original_name); if (error_found) return 1; } @@ -16190,42 +16174,6 @@ resolve_qualified_name (name, context) } #endif -/* Mark P, which is really a `struct parser_ctxt **' for GC. */ - -static void -mark_parser_ctxt (p) - void *p; -{ - struct parser_ctxt *pc = *((struct parser_ctxt **) p); -#ifndef JC1_LITE - size_t i; -#endif - - if (!pc) - return; - -#ifndef JC1_LITE - for (i = 0; i < ARRAY_SIZE (pc->modifier_ctx); ++i) - ggc_mark_tree (pc->modifier_ctx[i]); - ggc_mark_tree (pc->class_type); - ggc_mark_tree (pc->function_decl); - ggc_mark_tree (pc->package); - ggc_mark_tree (pc->class_list); - ggc_mark_tree (pc->current_parsed_class); - ggc_mark_tree (pc->current_parsed_class_un); - ggc_mark_tree (pc->non_static_initialized); - ggc_mark_tree (pc->static_initialized); - ggc_mark_tree (pc->instance_initializers); - ggc_mark_tree (pc->import_list); - ggc_mark_tree (pc->import_demand_list); - ggc_mark_tree (pc->current_loop); - ggc_mark_tree (pc->current_labeled_block); -#endif /* JC1_LITE */ - - if (pc->next) - mark_parser_ctxt (&pc->next); -} - void init_src_parse () { diff --git a/gcc/mkdeps.c b/gcc/mkdeps.c index 26504e1..0c573cd 100644 --- a/gcc/mkdeps.c +++ b/gcc/mkdeps.c @@ -291,3 +291,77 @@ deps_phony_targets (d, fp) putc ('\n', fp); } } + +/* Write out a deps buffer to a file, in a form that can be read back + with deps_restore. Returns nonzero on error, in which case the + error number will be in errno. */ + +int +deps_save (deps, f) + struct deps *deps; + FILE *f; +{ + unsigned int i; + + /* The cppreader structure contains makefile dependences. Write out this + structure. */ + + /* The number of dependences. */ + if (fwrite (&deps->ndeps, sizeof (deps->ndeps), 1, f) != 1) + return -1; + /* The length of each dependence followed by the string. */ + for (i = 0; i < deps->ndeps; i++) + { + size_t num_to_write = strlen (deps->depv[i]); + if (fwrite (&num_to_write, sizeof (size_t), 1, f) != 1) + return -1; + if (fwrite (deps->depv[i], num_to_write, 1, f) != 1) + return -1; + } + + return 0; +} + +/* Read back dependency information written with deps_save into + the deps buffer. The third argument may be NULL, in which case + the dependency information is just skipped, or it may be a filename, + in which case that filename is skipped. */ + +int +deps_restore (deps, fd, self) + struct deps *deps; + FILE *fd; + const char *self; +{ + unsigned int i, count; + size_t num_to_read; + size_t buf_size = 512; + char *buf = (char *) xmalloc (buf_size); + + /* Number of dependences. */ + if (fread (&count, 1, sizeof (count), fd) != sizeof (count)) + return -1; + + /* The length of each dependence string, followed by the string. */ + for (i = 0; i < count; i++) + { + /* Read in # bytes in string. */ + if (fread (&num_to_read, 1, sizeof (size_t), fd) != sizeof (size_t)) + return -1; + if (buf_size < num_to_read + 1) + { + buf_size = num_to_read + 1 + 127; + buf = xrealloc (buf, buf_size); + } + if (fread (buf, 1, num_to_read, fd) != num_to_read) + return -1; + buf[num_to_read] = '\0'; + + /* Generate makefile dependencies from .pch if -nopch-deps. */ + if (self != NULL && strcmp (buf, self) != 0) + deps_add_dep (deps, buf); + } + + free (buf); + return 0; +} diff --git a/gcc/mkdeps.h b/gcc/mkdeps.h index fa79b86..2be8f81 100644 --- a/gcc/mkdeps.h +++ b/gcc/mkdeps.h @@ -53,6 +53,17 @@ extern void deps_add_dep PARAMS ((struct deps *, const char *)); extern void deps_write PARAMS ((const struct deps *, FILE *, unsigned int)); +/* Write out a deps buffer to a file, in a form that can be read back + with deps_restore. Returns nonzero on error, in which case the + error number will be in errno. */ +extern int deps_save PARAMS ((struct deps *, FILE *)); + +/* Read back dependency information written with deps_save into + the deps buffer. The third argument may be NULL, in which case + the dependency information is just skipped, or it may be a filename, + in which case that filename is skipped. */ +extern int deps_restore PARAMS ((struct deps *, FILE *, const char *)); + /* For each dependency *except the first*, emit a dummy rule for that file, causing it to depend on nothing. This is used to work around the intermediate-file deletion misfeature in Make, in some diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 3f0d339..3a5de01 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -56,6 +56,7 @@ Boston, MA 02111-1307, USA. */ #include "output.h" #include "toplev.h" #include "ggc.h" +#include "varray.h" #include "debug.h" #include "target.h" #include "diagnostic.h" diff --git a/gcc/optabs.h b/gcc/optabs.h index e3890fe..2ff8fec 100644 --- a/gcc/optabs.h +++ b/gcc/optabs.h @@ -1,5 +1,5 @@ /* Definitions for code generation pass of GNU compiler. - Copyright (C) 2001 Free Software Foundation, Inc. + Copyright (C) 2001, 2002 Free Software Foundation, Inc. This file is part of GCC. @@ -246,7 +246,7 @@ extern enum insn_code reload_in_optab[NUM_MACHINE_MODES]; extern enum insn_code reload_out_optab[NUM_MACHINE_MODES]; /* Contains the optab used for each rtx code. */ -extern optab code_to_optab[NUM_RTX_CODE + 1]; +extern GTY(()) optab code_to_optab[NUM_RTX_CODE + 1]; typedef rtx (*rtxfun) PARAMS ((rtx)); diff --git a/gcc/stringpool.c b/gcc/stringpool.c index f3b34b1..1edb46f 100644 --- a/gcc/stringpool.c +++ b/gcc/stringpool.c @@ -1,5 +1,5 @@ /* String pool for GCC. - Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GCC. @@ -50,7 +50,6 @@ static struct obstack string_stack; static hashnode alloc_node PARAMS ((hash_table *)); static int mark_ident PARAMS ((struct cpp_reader *, hashnode, const PTR)); -static void mark_ident_hash PARAMS ((void *)); /* Initialize the string pool. */ void @@ -60,7 +59,6 @@ init_stringpool () ident_hash = ht_create (14); ident_hash->alloc_node = alloc_node; gcc_obstack_init (&string_stack); - ggc_add_root (&ident_hash, 1, sizeof ident_hash, mark_ident_hash); } /* Allocate a hash node. */ @@ -160,15 +158,94 @@ mark_ident (pfile, h, v) hashnode h; const PTR v ATTRIBUTE_UNUSED; { - ggc_mark_tree (HT_IDENT_TO_GCC_IDENT (h)); + gt_ggc_m_9tree_node (HT_IDENT_TO_GCC_IDENT (h)); return 1; } -/* Mark all identifiers for GC. */ +/* Mark the trees hanging off the identifier node for GGC. These are + handled specially (not using gengtype) because of the special + treatment for strings. */ -static void -mark_ident_hash (arg) - PTR arg ATTRIBUTE_UNUSED; +void +ggc_mark_stringpool () { ht_forall (ident_hash, mark_ident, NULL); } + +/* Strings are _not_ GCed, but this routine exists so that a separate + roots table isn't needed for the few global variables that refer + to strings. */ + +void +gt_ggc_m_S (x) + void *x ATTRIBUTE_UNUSED; +{ +} + +/* Pointer-walking routine for strings (not very interesting, since + strings don't contain pointers). */ + +void +gt_pch_p_S (obj, x, op, cookie) + void *obj ATTRIBUTE_UNUSED; + void *x ATTRIBUTE_UNUSED; + gt_pointer_operator op ATTRIBUTE_UNUSED; + void *cookie ATTRIBUTE_UNUSED; +{ +} + +/* PCH pointer-walking routine for strings. */ + +void +gt_pch_n_S (x) + const void *x; +{ + gt_pch_note_object ((void *)x, (void *)x, >_pch_p_S); +} + +/* Handle saving and restoring the string pool for PCH. */ + +struct string_pool_data GTY(()) +{ + tree * GTY((length ("%h.nslots"))) entries; + unsigned int nslots; + unsigned int nelements; +}; + +static GTY(()) struct string_pool_data * spd; + +void +gt_pch_save_stringpool () +{ + unsigned int i; + + spd = ggc_alloc (sizeof (*spd)); + spd->nslots = ident_hash->nslots; + spd->nelements = ident_hash->nelements; + spd->entries = ggc_alloc (sizeof (tree *) * spd->nslots); + for (i = 0; i < spd->nslots; i++) + if (ident_hash->entries[i] != NULL) + spd->entries[i] = HT_IDENT_TO_GCC_IDENT (ident_hash->entries[i]); + else + spd->entries[i] = NULL; +} + +void +gt_pch_restore_stringpool () +{ + unsigned int i; + + ident_hash->nslots = spd->nslots; + ident_hash->nelements = spd->nelements; + ident_hash->entries = xrealloc (ident_hash->entries, + sizeof (hashnode) * spd->nslots); + for (i = 0; i < spd->nslots; i++) + if (spd->entries[i] != NULL) + ident_hash->entries[i] = GCC_IDENT_TO_HT_IDENT (spd->entries[i]); + else + ident_hash->entries[i] = NULL; + + spd = NULL; +} + +#include "gt-stringpool.h" diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8168b98..e1c6e02 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,87 @@ +2003-01-09 Geoffrey Keating + + Merge from pch-branch: + + 2002-12-23 Geoffrey Keating + + * gcc.dg/pch/cpp-1.h: New. + * gcc.dg/pch/cpp-1.c: New. + * gcc.dg/pch/cpp-2.h: New. + * gcc.dg/pch/cpp-2.c: New. + + 2002-11-19 Geoffrey Keating + + * gcc.dg/pch/except-1.h: New. + * gcc.dg/pch/except-1.c: New. + + 2002-11-13 Geoffrey Keating + + * gcc.dg/pch/pch.exp: Ensure that .hp doesn't exist before + running test. + * gcc.dg/pch: Include *.hp not *.h. + * gcc.dg/pch/system-1.h: New. + * gcc.dg/pch/system-1.c: New. + + 2002-11-11 Geoffrey Keating + + * gcc.dg/pch/pch.exp: Compare .s files with/without PCH, + rather than trying to build and run a program using PCH. + * gcc.dg/pch: Remove dg-do commands from test files. + + 2002-11-08 Geoffrey Keating + + * gcc.dg/pch/macro-3.c: New. + * gcc.dg/pch/macro-3.h: New. + + 2002-11-04 Geoffrey Keating + + * gcc.dg/pch/common-1.c: New. + * gcc.dg/pch/common-1.h: New. + * gcc.dg/pch/decl-1.c: New. + * gcc.dg/pch/decl-1.h: New. + * gcc.dg/pch/decl-2.c: New. + * gcc.dg/pch/decl-2.h: New. + * gcc.dg/pch/decl-3.c: New. + * gcc.dg/pch/decl-3.h: New. + * gcc.dg/pch/decl-4.c: New. + * gcc.dg/pch/decl-4.h: New. + * gcc.dg/pch/decl-5.c: New. + * gcc.dg/pch/decl-5.h: New. + * gcc.dg/pch/global-1.c: New. + * gcc.dg/pch/global-1.h: New. + * gcc.dg/pch/inline-1.c: New. + * gcc.dg/pch/inline-1.h: New. + * gcc.dg/pch/inline-2.c: New. + * gcc.dg/pch/inline-2.h: New. + * gcc.dg/pch/static-1.c: New. + * gcc.dg/pch/static-1.h: New. + * gcc.dg/pch/static-2.c: New. + * gcc.dg/pch/static-2.h: New. + + 2002-09-01 Geoffrey Keating + + * g++.dg/pch/pch.exp: Better handle failing testcases. + * gcc.dg/pch/pch.exp: Likewise. + * gcc.dg/pch/macro-1.c: New. + * gcc.dg/pch/macro-1.h: New. + * gcc.dg/pch/macro-2.c: New. + * gcc.dg/pch/macro-2.h: New. + + 2002-08-27 Geoffrey Keating + + * g++.dg/dg.exp: Treat files in pch/ specially. + * g++.dg/pch/pch.exp: New file. + * g++.dg/pch/empty.H: New file. + * g++.dg/pch/empty.C: New file. + * lib/g++-dg.exp (g++-dg-test): Add case for when $do_what is + "precompile". + + * gcc.dg/pch/pch.exp: New file. + * gcc.dg/pch/empty.h: New file. + * gcc.dg/pch/empty.c: New file. + * lib/gcc-dg.exp (gcc-dg-test): Add case for when $do_what is + "precompile". + 2003-01-09 Kriang Lerdsuwanakij * g++.dg/template/friend14.C: New test. diff --git a/gcc/testsuite/g++.dg/dg.exp b/gcc/testsuite/g++.dg/dg.exp index ea96197..d983960 100644 --- a/gcc/testsuite/g++.dg/dg.exp +++ b/gcc/testsuite/g++.dg/dg.exp @@ -35,6 +35,7 @@ set tests [prune $tests $srcdir/$subdir/bprob/*] set tests [prune $tests $srcdir/$subdir/compat/*] set tests [prune $tests $srcdir/$subdir/debug/*] set tests [prune $tests $srcdir/$subdir/gcov/*] +set tests [prune $tests $srcdir/$subdir/pch/*] set tests [prune $tests $srcdir/$subdir/special/*] set tests [prune $tests $srcdir/$subdir/tls/*] diff --git a/gcc/testsuite/g++.dg/pch/empty.C b/gcc/testsuite/g++.dg/pch/empty.C new file mode 100644 index 0000000..7aef099 --- /dev/null +++ b/gcc/testsuite/g++.dg/pch/empty.C @@ -0,0 +1,5 @@ +#include "empty.Hp" +int main() +{ + return 0; +} diff --git a/gcc/testsuite/g++.dg/pch/empty.H b/gcc/testsuite/g++.dg/pch/empty.H new file mode 100644 index 0000000..e69de29 diff --git a/gcc/testsuite/g++.dg/pch/pch.exp b/gcc/testsuite/g++.dg/pch/pch.exp new file mode 100644 index 0000000..8507e35 --- /dev/null +++ b/gcc/testsuite/g++.dg/pch/pch.exp @@ -0,0 +1,100 @@ +# Copyright (C) 1997, 2002 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# GCC testsuite for precompiled header interaction, +# that uses the `dg.exp' driver. + +# Load support procs. +load_lib "g++-dg.exp" + +# Initialize `dg'. +dg-init + +set old_dg_do_what_default "${dg-do-what-default}" + +# Main loop. +foreach test [lsort [glob -nocomplain $srcdir/$subdir/*.C]] { + global runtests dg-do-what-default + + # If we're only testing specific files and this isn't one of them, skip it. + if ![runtest_file_p $runtests $test] { + continue + } + set nshort [file tail [file dirname $test]]/[file tail $test] + set bname "[file rootname [file tail $test]]" + + catch { file delete "$bname.Hp.pch" } + catch { file delete "$bname.H.pch" } + catch { file delete "$bname.s" } + catch { file delete "$bname.s-pch" } + catch { file delete "$bname.Hp" } + + # We don't try to use the loop-optimizing options, since they are highly + # unlikely to make any difference to PCH. + foreach flags { "-g" "-O2 -g" "-O2" } { + verbose "Testing $nshort, $flags" 1 + + # For the header files, the default is to precompile. + set dg-do-what-default precompile + dg-test -keep-output "[file rootname $test].H" $flags "" + + # For the rest, the default is to compile to .s. + set dg-do-what-default compile + + if { [ file exists "$bname.H.pch" ] } { + # To ensure that the PCH is used, not the original header, + # the actual PCH file is renamed to ".Hp.pch". + file rename "$bname.H.pch" "$bname.Hp.pch" + if { [ is_remote host ] } { + remote_download host "$bname.Hp.pch" + } + + dg-test -keep-output $test $flags "-I." + file delete "$bname.Hp.pch" + if { [ file exists "$bname.s" ] } { + file rename "$bname.s" "$bname.s-pch" + if { [ is_remote host ] } { + remote_upload host "[file rootname $test].H" "$bname.Hp" + } else { + file copy "[file rootname $test].H" "$bname.Hp" + } + dg-test -keep-output $test $flags "-I." + remote_file host delete "$bname.Hp" + set tmp [ diff "$bname.s" "$bname.s-pch" ] + if { $tmp == 0 } { + untested "$nshort $flags assembly comparison" + } elseif { $tmp == 1 } { + pass "$nshort $flags assembly comparison" + } else { + fail "$nshort $flags assembly comparison" + } + file delete "$bname.s" + file delete "$bname.s-pch" + } else { + untested "$nshort $flags assembly comparison" + } + + } else { + untested $nshort + untested "$nshort $flags assembly comparison" + } + } +} + +set dg-do-what-default "$old_dg_do_what_default" + +# All done. +dg-finish diff --git a/gcc/testsuite/g++.dg/pch/system-1.C b/gcc/testsuite/g++.dg/pch/system-1.C new file mode 100644 index 0000000..a0444bc --- /dev/null +++ b/gcc/testsuite/g++.dg/pch/system-1.C @@ -0,0 +1,7 @@ +#include "system-1.Hp" + +int main() +{ + std::cout << "hello world!" << '\n'; + return 0; +} diff --git a/gcc/testsuite/g++.dg/pch/system-1.H b/gcc/testsuite/g++.dg/pch/system-1.H new file mode 100644 index 0000000..604782e --- /dev/null +++ b/gcc/testsuite/g++.dg/pch/system-1.H @@ -0,0 +1 @@ +#include diff --git a/gcc/testsuite/gcc.dg/pch/common-1.c b/gcc/testsuite/gcc.dg/pch/common-1.c new file mode 100644 index 0000000..dcf148a --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/common-1.c @@ -0,0 +1,3 @@ +#include "common-1.hp" +int foo2 = 3; +int zz = 2; diff --git a/gcc/testsuite/gcc.dg/pch/common-1.h b/gcc/testsuite/gcc.dg/pch/common-1.h new file mode 100644 index 0000000..971e199 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/common-1.h @@ -0,0 +1,3 @@ +static int foo1 = 9; +int foo2; +extern int zz; diff --git a/gcc/testsuite/gcc.dg/pch/cpp-1.c b/gcc/testsuite/gcc.dg/pch/cpp-1.c new file mode 100644 index 0000000..43256ca --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/cpp-1.c @@ -0,0 +1,4 @@ +#include "cpp-1.hp" +#if !defined(__GNUC__) +panic! panic! +#endif diff --git a/gcc/testsuite/gcc.dg/pch/cpp-1.h b/gcc/testsuite/gcc.dg/pch/cpp-1.h new file mode 100644 index 0000000..6e25b02 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/cpp-1.h @@ -0,0 +1 @@ +/* Empty. */ diff --git a/gcc/testsuite/gcc.dg/pch/cpp-2.c b/gcc/testsuite/gcc.dg/pch/cpp-2.c new file mode 100644 index 0000000..b76c22c --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/cpp-2.c @@ -0,0 +1,4 @@ +/* { dg-options "-Wunknown-pragmas -I." } */ +#include "cpp-2.hp" +#pragma GCC poison not_used + diff --git a/gcc/testsuite/gcc.dg/pch/cpp-2.h b/gcc/testsuite/gcc.dg/pch/cpp-2.h new file mode 100644 index 0000000..6e25b02 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/cpp-2.h @@ -0,0 +1 @@ +/* Empty. */ diff --git a/gcc/testsuite/gcc.dg/pch/decl-1.c b/gcc/testsuite/gcc.dg/pch/decl-1.c new file mode 100644 index 0000000..e412070 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/decl-1.c @@ -0,0 +1,2 @@ +#include "decl-1.hp" +int main(void) { return foo; } diff --git a/gcc/testsuite/gcc.dg/pch/decl-1.h b/gcc/testsuite/gcc.dg/pch/decl-1.h new file mode 100644 index 0000000..399f5d3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/decl-1.h @@ -0,0 +1 @@ +extern int foo; diff --git a/gcc/testsuite/gcc.dg/pch/decl-2.c b/gcc/testsuite/gcc.dg/pch/decl-2.c new file mode 100644 index 0000000..c374a17 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/decl-2.c @@ -0,0 +1,2 @@ +#include "decl-2.hp" +int main(void) { return fun (1, 2); } diff --git a/gcc/testsuite/gcc.dg/pch/decl-2.h b/gcc/testsuite/gcc.dg/pch/decl-2.h new file mode 100644 index 0000000..99c3726 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/decl-2.h @@ -0,0 +1,3 @@ +extern int fun (int a, int b); + + diff --git a/gcc/testsuite/gcc.dg/pch/decl-3.c b/gcc/testsuite/gcc.dg/pch/decl-3.c new file mode 100644 index 0000000..9c95b9a --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/decl-3.c @@ -0,0 +1,11 @@ +#include "decl-3.hp" + +foo_p bar (void) +{ + return foop; +} + +struct foo *bar2 (void) +{ + return foop; +} diff --git a/gcc/testsuite/gcc.dg/pch/decl-3.h b/gcc/testsuite/gcc.dg/pch/decl-3.h new file mode 100644 index 0000000..787d480 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/decl-3.h @@ -0,0 +1,3 @@ +struct foo; +typedef struct foo *foo_p; +extern foo_p foop; diff --git a/gcc/testsuite/gcc.dg/pch/decl-4.c b/gcc/testsuite/gcc.dg/pch/decl-4.c new file mode 100644 index 0000000..3efe382 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/decl-4.c @@ -0,0 +1,9 @@ +#include "decl-4.hp" + +int bar (foo_p f) +{ + if (f->a + foop->a) + return f->c->b + foop->b; + else + return foop->c->b + f->a; +} diff --git a/gcc/testsuite/gcc.dg/pch/decl-4.h b/gcc/testsuite/gcc.dg/pch/decl-4.h new file mode 100644 index 0000000..3fb2200 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/decl-4.h @@ -0,0 +1,7 @@ +typedef struct foo { + int a; + char b; + struct foo *c; +} foo_s; +typedef struct foo *foo_p; +extern foo_p foop; diff --git a/gcc/testsuite/gcc.dg/pch/decl-5.c b/gcc/testsuite/gcc.dg/pch/decl-5.c new file mode 100644 index 0000000..f94b33a --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/decl-5.c @@ -0,0 +1,2 @@ +#include "decl-5.hp" +static int (*t)(void) = foo; diff --git a/gcc/testsuite/gcc.dg/pch/decl-5.h b/gcc/testsuite/gcc.dg/pch/decl-5.h new file mode 100644 index 0000000..914983c --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/decl-5.h @@ -0,0 +1 @@ +extern int foo(void); diff --git a/gcc/testsuite/gcc.dg/pch/empty.c b/gcc/testsuite/gcc.dg/pch/empty.c new file mode 100644 index 0000000..330876c --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/empty.c @@ -0,0 +1,8 @@ +/* Yes, it's called "empty" because it has no contents at all. + Even this comment goes here, rather than in empty.h. */ +#include "empty.hp" + +int main(void) +{ + return 0; +} diff --git a/gcc/testsuite/gcc.dg/pch/empty.h b/gcc/testsuite/gcc.dg/pch/empty.h new file mode 100644 index 0000000..e69de29 diff --git a/gcc/testsuite/gcc.dg/pch/except-1.c b/gcc/testsuite/gcc.dg/pch/except-1.c new file mode 100644 index 0000000..0332609 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/except-1.c @@ -0,0 +1,7 @@ +/* { dg-options "-fexceptions -I." } */ +#include "except-1.hp" + +int main(void) +{ + return foo(1); +} diff --git a/gcc/testsuite/gcc.dg/pch/except-1.h b/gcc/testsuite/gcc.dg/pch/except-1.h new file mode 100644 index 0000000..33a893d --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/except-1.h @@ -0,0 +1,6 @@ +/* { dg-options "-fexceptions" } */ +extern inline int +foo(int a) +{ + return a + 1; +} diff --git a/gcc/testsuite/gcc.dg/pch/global-1.c b/gcc/testsuite/gcc.dg/pch/global-1.c new file mode 100644 index 0000000..4cab062 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/global-1.c @@ -0,0 +1,2 @@ +#include "global-1.hp" +const int bar = 3; diff --git a/gcc/testsuite/gcc.dg/pch/global-1.h b/gcc/testsuite/gcc.dg/pch/global-1.h new file mode 100644 index 0000000..26efffc --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/global-1.h @@ -0,0 +1 @@ +const int foo = 2; diff --git a/gcc/testsuite/gcc.dg/pch/inline-1.c b/gcc/testsuite/gcc.dg/pch/inline-1.c new file mode 100644 index 0000000..7fc32d7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/inline-1.c @@ -0,0 +1,10 @@ +#include "inline-1.hp" +int bar(int a, int b) +{ + return foo(a) + b; +} + +int baz(void) +{ + return foo(3); +} diff --git a/gcc/testsuite/gcc.dg/pch/inline-1.h b/gcc/testsuite/gcc.dg/pch/inline-1.h new file mode 100644 index 0000000..e8f1d6f --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/inline-1.h @@ -0,0 +1,5 @@ +extern inline int +foo(int a) +{ + return a * 2 + 1; +} diff --git a/gcc/testsuite/gcc.dg/pch/inline-2.c b/gcc/testsuite/gcc.dg/pch/inline-2.c new file mode 100644 index 0000000..7792c82 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/inline-2.c @@ -0,0 +1,12 @@ +#include "inline-2.hp" +extern inline char +bar(int a) +{ + return foo(a)[0]; +} + +extern inline char +baz(void) +{ + return foo(0)[0]; +} diff --git a/gcc/testsuite/gcc.dg/pch/inline-2.h b/gcc/testsuite/gcc.dg/pch/inline-2.h new file mode 100644 index 0000000..7d90c63 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/inline-2.h @@ -0,0 +1,5 @@ +extern inline const char * +foo(int a) +{ + return "abcdefgh"+a; +} diff --git a/gcc/testsuite/gcc.dg/pch/macro-1.c b/gcc/testsuite/gcc.dg/pch/macro-1.c new file mode 100644 index 0000000..3775004 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/macro-1.c @@ -0,0 +1,6 @@ +#include "macro-1.hp" + +int main(void) +{ + return DEFINED_VALUE + 1 - DEFINED_PARAM (3); +} diff --git a/gcc/testsuite/gcc.dg/pch/macro-1.h b/gcc/testsuite/gcc.dg/pch/macro-1.h new file mode 100644 index 0000000..5d5b3f4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/macro-1.h @@ -0,0 +1,2 @@ +#define DEFINED_VALUE 3 +#define DEFINED_PARAM(x) (x+1) diff --git a/gcc/testsuite/gcc.dg/pch/macro-2.c b/gcc/testsuite/gcc.dg/pch/macro-2.c new file mode 100644 index 0000000..d058e2b --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/macro-2.c @@ -0,0 +1,8 @@ +#define DEFINED_VALUE_2 3 + +#include "macro-2.hp" + +int main(void) +{ + return DEFINED_VALUE - DEFINED_VALUE_2; +} diff --git a/gcc/testsuite/gcc.dg/pch/macro-2.h b/gcc/testsuite/gcc.dg/pch/macro-2.h new file mode 100644 index 0000000..6152a84 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/macro-2.h @@ -0,0 +1,2 @@ +#define DEFINED_VALUE 3 + diff --git a/gcc/testsuite/gcc.dg/pch/macro-3.c b/gcc/testsuite/gcc.dg/pch/macro-3.c new file mode 100644 index 0000000..40ee46e --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/macro-3.c @@ -0,0 +1,8 @@ +#define DEFINED_FUNC_2(x) (3 + (x)) + +#include "macro-3.hp" + +int main(void) +{ + return DEFINED_FUNC (1) - DEFINED_FUNC_2 (-1); +} diff --git a/gcc/testsuite/gcc.dg/pch/macro-3.h b/gcc/testsuite/gcc.dg/pch/macro-3.h new file mode 100644 index 0000000..d394792 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/macro-3.h @@ -0,0 +1,2 @@ +#define DEFINED_FUNC(x) 3 - (x) + diff --git a/gcc/testsuite/gcc.dg/pch/pch.exp b/gcc/testsuite/gcc.dg/pch/pch.exp new file mode 100644 index 0000000..69422ca --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/pch.exp @@ -0,0 +1,100 @@ +# Copyright (C) 1997, 2002 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# GCC testsuite for precompiled header interaction, +# that uses the `dg.exp' driver. + +# Load support procs. +load_lib gcc-dg.exp + +# Initialize `dg'. +dg-init + +set old_dg_do_what_default "${dg-do-what-default}" + +# Main loop. +foreach test [lsort [glob -nocomplain $srcdir/$subdir/*.c]] { + global runtests torture_without_loops dg-do-what-default + + # If we're only testing specific files and this isn't one of them, skip it. + if ![runtest_file_p $runtests $test] { + continue + } + set nshort [file tail [file dirname $test]]/[file tail $test] + set bname "[file rootname [file tail $test]]" + + catch { file delete "$bname.hp.pch" } + catch { file delete "$bname.h.pch" } + catch { file delete "$bname.s" } + catch { file delete "$bname.s-pch" } + catch { file delete "$bname.hp" } + + # We don't try to use the loop-optimizing options, since they are highly + # unlikely to make any difference to PCH. + foreach flags $torture_without_loops { + verbose "Testing $nshort, $flags" 1 + + # For the header files, the default is to precompile. + set dg-do-what-default precompile + dg-test -keep-output "[file rootname $test].h" $flags "" + + # For the rest, the default is to compile to .s. + set dg-do-what-default compile + + if { [ file exists "$bname.h.pch" ] } { + # To ensure that the PCH is used, not the original header, + # the actual PCH file is renamed to ".hp.pch". + file rename "$bname.h.pch" "$bname.hp.pch" + if { [ is_remote host ] } { + remote_download host "$bname.hp.pch" + } + + dg-test -keep-output $test $flags "-I." + file delete "$bname.hp.pch" + if { [ file exists "$bname.s" ] } { + file rename "$bname.s" "$bname.s-pch" + if { [ is_remote host ] } { + remote_upload host "[file rootname $test].h" "$bname.hp" + } else { + file copy "[file rootname $test].h" "$bname.hp" + } + dg-test -keep-output $test $flags "-I." + remote_file host delete "$bname.hp" + set tmp [ diff "$bname.s" "$bname.s-pch" ] + if { $tmp == 0 } { + untested "$nshort $flags assembly comparison" + } elseif { $tmp == 1 } { + pass "$nshort $flags assembly comparison" + } else { + fail "$nshort $flags assembly comparison" + } + file delete "$bname.s" + file delete "$bname.s-pch" + } else { + untested "$nshort $flags assembly comparison" + } + + } else { + untested $nshort + untested "$nshort $flags assembly comparison" + } + } +} + +set dg-do-what-default "$old_dg_do_what_default" + +# All done. +dg-finish diff --git a/gcc/testsuite/gcc.dg/pch/static-1.c b/gcc/testsuite/gcc.dg/pch/static-1.c new file mode 100644 index 0000000..c1816e9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/static-1.c @@ -0,0 +1,6 @@ +#include "static-1.hp" +static int bar(void) +{ + static int counter; + return counter++; +} diff --git a/gcc/testsuite/gcc.dg/pch/static-1.h b/gcc/testsuite/gcc.dg/pch/static-1.h new file mode 100644 index 0000000..08cc439 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/static-1.h @@ -0,0 +1,5 @@ +static int foo(void) +{ + static int counter; + return counter++; +} diff --git a/gcc/testsuite/gcc.dg/pch/static-2.c b/gcc/testsuite/gcc.dg/pch/static-2.c new file mode 100644 index 0000000..afda874 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/static-2.c @@ -0,0 +1,6 @@ +#include "static-2.hp" +int bar(void) +{ + static int counter; + return counter++; +} diff --git a/gcc/testsuite/gcc.dg/pch/static-2.h b/gcc/testsuite/gcc.dg/pch/static-2.h new file mode 100644 index 0000000..08cc439 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/static-2.h @@ -0,0 +1,5 @@ +static int foo(void) +{ + static int counter; + return counter++; +} diff --git a/gcc/testsuite/gcc.dg/pch/system-1.c b/gcc/testsuite/gcc.dg/pch/system-1.c new file mode 100644 index 0000000..096fe59 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/system-1.c @@ -0,0 +1,6 @@ +#include "system-1.hp" +int main(void) +{ + puts ("hello world!"); + exit (0); +} diff --git a/gcc/testsuite/gcc.dg/pch/system-1.h b/gcc/testsuite/gcc.dg/pch/system-1.h new file mode 100644 index 0000000..fbfff34 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pch/system-1.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/gcc/testsuite/lib/g++-dg.exp b/gcc/testsuite/lib/g++-dg.exp index 8be839e..2fad5d1 100644 --- a/gcc/testsuite/lib/g++-dg.exp +++ b/gcc/testsuite/lib/g++-dg.exp @@ -37,6 +37,10 @@ proc g++-dg-test { prog do_what extra_tool_flags } { set compile_type "object" set output_file "[file rootname [file tail $prog]].o" } + "precompile" { + set compile_type "precompiled_header" + set output_file "[file tail $prog].pch" + } "link" { set compile_type "executable" set output_file "[file rootname [file tail $prog]].exe" diff --git a/gcc/testsuite/lib/gcc-dg.exp b/gcc/testsuite/lib/gcc-dg.exp index 403fefc..dd130b9 100644 --- a/gcc/testsuite/lib/gcc-dg.exp +++ b/gcc/testsuite/lib/gcc-dg.exp @@ -69,6 +69,10 @@ proc gcc-dg-test { prog do_what extra_tool_flags } { set compile_type "object" set output_file "[file rootname [file tail $prog]].o" } + "precompile" { + set compile_type "precompiled_header" + set output_file "[file tail $prog].pch" + } "link" { set compile_type "executable" set output_file "[file rootname [file tail $prog]].exe" diff --git a/gcc/toplev.c b/gcc/toplev.c index ccc061f..f98fc36 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -4666,7 +4666,7 @@ init_asm_output (name) if (!strcmp (asm_file_name, "-")) asm_out_file = stdout; else - asm_out_file = fopen (asm_file_name, "w"); + asm_out_file = fopen (asm_file_name, "w+"); if (asm_out_file == 0) fatal_io_error ("can't open %s for writing", asm_file_name); } diff --git a/gcc/tree.c b/gcc/tree.c index 0247bb9..f1549ab 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -136,8 +136,8 @@ void init_ttree () { /* Initialize the hash table of types. */ - type_hash_table = htab_create (TYPE_HASH_INITIAL_SIZE, type_hash_hash, - type_hash_eq, 0); + type_hash_table = htab_create_ggc (TYPE_HASH_INITIAL_SIZE, type_hash_hash, + type_hash_eq, 0); } diff --git a/gcc/tree.h b/gcc/tree.h index 6075d83..d8bc1a8 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -98,7 +98,7 @@ enum built_in_function extern const char *const built_in_names[(int) END_BUILTINS]; /* An array of _DECL trees for the above. */ -extern tree built_in_decls[(int) END_BUILTINS]; +extern GTY(()) tree built_in_decls[(int) END_BUILTINS]; /* The definition of tree nodes fills the next several pages. */ @@ -1273,9 +1273,9 @@ struct tree_type GTY(()) tree pointer_to; tree reference_to; union tree_type_symtab { - int address; + int GTY ((tag ("0"))) address; char * GTY ((tag ("1"))) pointer; - struct die_struct * GTY ((tag ("2"), skip (""))) die; + struct die_struct * GTY ((tag ("2"))) die; } GTY ((desc ("debug_hooks == &sdb_debug_hooks ? 1 : debug_hooks == &dwarf2_debug_hooks ? 2 : 0"), descbits ("2"))) symtab; tree name; @@ -1881,7 +1881,7 @@ struct tree_decl GTY(()) struct function * GTY ((tag ("FUNCTION_DECL"))) f; rtx GTY ((tag ("PARM_DECL"))) r; tree GTY ((tag ("FIELD_DECL"))) t; - int i; + int GTY ((tag ("VAR_DECL"))) i; } GTY ((desc ("TREE_CODE((tree) &(%0))"))) u2; /* In a FUNCTION_DECL, this is DECL_SAVED_TREE. */ diff --git a/gcc/varasm.c b/gcc/varasm.c index 948b1a9..673030d 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -107,12 +107,12 @@ struct varasm_status GTY(()) /* Number for making the label on the next constant that is stored in memory. */ -int const_labelno; +static GTY(()) int const_labelno; /* Number for making the label on the next static variable internal to a function. */ -int var_labelno; +static GTY(()) int var_labelno; /* Carry information from ASM_DECLARE_OBJECT_NAME to ASM_FINISH_DECLARE_OBJECT. */ @@ -179,7 +179,7 @@ static bool asm_emit_uninitialised PARAMS ((tree, const char*, int, int)); static void resolve_unique_section PARAMS ((tree, int, int)); static void mark_weak PARAMS ((tree)); -static enum in_section { no_section, in_text, in_data, in_named +enum in_section { no_section, in_text, in_data, in_named #ifdef BSS_SECTION_ASM_OP , in_bss #endif @@ -195,7 +195,8 @@ static enum in_section { no_section, in_text, in_data, in_named #ifdef EXTRA_SECTIONS , EXTRA_SECTIONS #endif -} in_section = no_section; +}; +static GTY(()) enum in_section in_section = no_section; /* Return a nonzero value if DECL has a section attribute. */ #ifndef IN_NAMED_SECTION @@ -205,18 +206,18 @@ static enum in_section { no_section, in_text, in_data, in_named #endif /* Text of section name when in_section == in_named. */ -static const char *in_named_name; +static GTY(()) const char *in_named_name; /* Hash table of flags that have been used for a particular named section. */ -struct in_named_entry +struct in_named_entry GTY(()) { const char *name; unsigned int flags; bool declared; }; -static htab_t in_named_htab; +static GTY((param_is (struct in_named_entry))) htab_t in_named_htab; /* Define functions like text_section for any extra sections. */ #ifdef EXTRA_SECTION_FUNCTIONS @@ -379,7 +380,7 @@ set_named_section_flags (section, flags) if (!entry) { - entry = (struct in_named_entry *) xmalloc (sizeof (*entry)); + entry = (struct in_named_entry *) ggc_alloc (sizeof (*entry)); *slot = entry; entry->name = ggc_strdup (section); entry->flags = flags; @@ -2119,7 +2120,7 @@ struct rtx_const GTY(()) ENUM_BITFIELD(kind) kind : 16; ENUM_BITFIELD(machine_mode) mode : 16; union rtx_const_un { - REAL_VALUE_TYPE du; + REAL_VALUE_TYPE GTY ((tag ("4"))) du; struct addr_const GTY ((tag ("1"))) addr; struct rtx_const_u_di { HOST_WIDE_INT high; @@ -4703,8 +4704,8 @@ init_varasm_once () { const_str_htab = htab_create_ggc (128, const_str_htab_hash, const_str_htab_eq, NULL); - in_named_htab = htab_create (31, in_named_entry_hash, - in_named_entry_eq, NULL); + in_named_htab = htab_create_ggc (31, in_named_entry_hash, + in_named_entry_eq, NULL); const_alias_set = new_alias_set (); } -- cgit v1.1