From d19dcb671529004ecd8a06e38a00d9b8fb380ccd Mon Sep 17 00:00:00 2001
From: Ken Raeburn <raeburn@cygnus>
Date: Wed, 18 Oct 1995 21:21:38 +0000
Subject: Use one active frag and one obstack per frag chain:

* frags.c (frags): Variable deleted.
(frag_alloc): New function.
(frag_grow, frag_more, frag_variant, frag_now_fix, frag_append_1_char): Refer
to frchain_now->frch_obstack instead of frags variable.
(frag_new): Ditto.  Verify that frch_last and frag_now match on entry and exit,
and that old frag_now has non-zero type.  Replace "know" uses with "assert".
Use frag_alloc instead of mucking with obstack alignment.
* frags.h (frags): Declaration deleted.
* subsegs.h (struct frchain): Add new field frch_frag_now.
* subsegs.c (frchains, dummy_frag, absolute_frchain): New static variables.
(subsegs_begin): Initialize frchains obstack.  Under gcc, don't give it any
stricter alignment than frchainS structures need.  Do not initialize frags
obstack.  Set frag_now to point to dummy_obstack.  Initialize absolute_frchain.
(subseg_set_rest): Save and restore frag_now in frch_frag_now field of
frchainS.  Don't create new frags on section switch, and use frag_alloc when
creating a new frag chain.  For absolute section, set frchain_now to
absolute_frchain.  Verify that frch_last and frag_now match on entry and exit.
Initialize per-chain obstack, and under gcc, set required alignment to that
needed by fragS structure.
* write.c (chain_frchains_together_1): Verify fr_type is nonzero.

In one test case of Mike's (i386-linux, over 300K lines of .s code with lots
of stabs records), run time and memory use are reduced by about 1/3.

Might introduce some problems in cases that use the frag obstacks in unusual
ways.  Test suite does pass for i386-linux and sparc-solaris targets though.
---
 gas/subsegs.c | 115 +++++++++++++++++++++++++++++-----------------------------
 1 file changed, 57 insertions(+), 58 deletions(-)

(limited to 'gas/subsegs.c')

diff --git a/gas/subsegs.c b/gas/subsegs.c
index e360d32..3280bcd 100644
--- a/gas/subsegs.c
+++ b/gas/subsegs.c
@@ -29,6 +29,8 @@
 
 frchainS *frchain_root, *frchain_now;
 
+static struct obstack frchains;
+
 #ifndef BFD_ASSEMBLER
 #ifdef MANY_SEGMENTS
 segment_info_type segment_info[SEG_MAXIMUM_ORDINAL];
@@ -67,6 +69,10 @@ static segment_info_type *und_seg_info;
 #endif /* BFD_ASSEMBLER */
 
 static void subseg_set_rest PARAMS ((segT, subsegT));
+
+static fragS dummy_frag;
+
+static frchainS absolute_frchain;
 
 void
 subsegs_begin ()
@@ -87,16 +93,17 @@ subsegs_begin ()
   know (SEG_MAXIMUM_ORDINAL == SEG_REGISTER);
 #endif
 
+  obstack_begin (&frchains, chunksize);
+#if __GNUC__ >= 2
+  obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1;
+#endif
+
   frchain_root = NULL;
   frchain_now = NULL;		/* Warn new_subseg() that we are booting. */
-  /* Fake up 1st frag.  It won't be used=> is ok if obstack...
-     pads the end of it for alignment. */
-  frag_now = (fragS *) obstack_alloc (&frags, SIZEOF_STRUCT_FRAG);
-  memset (frag_now, 0, SIZEOF_STRUCT_FRAG);
+
+  frag_now = &dummy_frag;
 
 #ifndef BFD_ASSEMBLER
-  /* This 1st frag will not be in any frchain.
-     We simply give subseg_new somewhere to scribble. */
   now_subseg = 42;		/* Lie for 1st call to subseg_new. */
 #ifdef MANY_SEGMENTS
   {
@@ -117,6 +124,11 @@ subsegs_begin ()
 #endif /* ! MANY_SEGMENTS */
 #endif /* ! BFD_ASSEMBLER */
 
+  absolute_frchain.frch_seg = absolute_section;
+  absolute_frchain.frch_subseg = 0;
+  absolute_frchain.fix_root = absolute_frchain.fix_tail = 0;
+  absolute_frchain.frch_frag_now = &zero_address_frag;
+  absolute_frchain.frch_root = absolute_frchain.frch_last = &zero_address_frag;
 }
 
 /*
@@ -137,6 +149,9 @@ subseg_change (seg, subseg)
   now_seg = seg;
   now_subseg = subseg;
 
+  if (now_seg == absolute_section)
+    return;
+
 #ifdef BFD_ASSEMBLER
   {
     segment_info_type *seginfo;
@@ -195,26 +210,29 @@ subseg_set_rest (seg, subseg)
   register fragS *former_last_fragP;
   register fragS *new_fragP;
 
-  if (frag_now)		/* If not bootstrapping. */
+  mri_common_symbol = NULL;
+
+  if (frag_now && frchain_now)
+    frchain_now->frch_frag_now = frag_now;
+
+  assert (frchain_now == 0
+	  || now_seg == undefined_section
+	  || now_seg == absolute_section
+	  || frchain_now->frch_last == frag_now);
+
+  subseg_change (seg, (int) subseg);
+
+  if (seg == absolute_section)
     {
-      frag_now->fr_fix = frag_now_fix ();
-      frag_wane (frag_now);	/* Close off any frag in old subseg. */
+      frchain_now = &absolute_frchain;
+      frag_now = &zero_address_frag;
+      return;
     }
-  /*
-   * It would be nice to keep an obstack for each subsegment, if we swap
-   * subsegments a lot. Hence we would have much fewer frag_wanes().
-   */
-  {
-    obstack_finish (&frags);
-    /*
-     * If we don't do the above, the next object we put on obstack frags
-     * will appear to start at the fr_literal of the current frag.
-     * Also, above ensures that the next object will begin on a
-     * address that is aligned correctly for the engine that runs
-     * this program.
-     */
-  }
-  subseg_change (seg, (int) subseg);
+
+  assert (frchain_now == 0
+	  || now_seg == undefined_section
+	  || frchain_now->frch_last == frag_now);
+
   /*
    * Attempt to find or make a frchain for that sub seg.
    * Crawl along chain of frchainSs, begins @ frchain_root.
@@ -259,16 +277,22 @@ subseg_set_rest (seg, subseg)
       /*
        * This should be the only code that creates a frchainS.
        */
-      newP = (frchainS *) obstack_alloc (&frags, sizeof (frchainS));
-      newP->frch_root = 0;
+      extern fragS *frag_alloc ();
+      newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS));
       newP->frch_subseg = subseg;
       newP->frch_seg = seg;
-      newP->frch_last = NULL;
 #ifdef BFD_ASSEMBLER
       newP->fix_root = NULL;
       newP->fix_tail = NULL;
 #endif
       obstack_begin (&newP->frch_obstack, 5000);
+#if __GNUC__ >= 2
+      obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1;
+#endif
+      newP->frch_frag_now = frag_alloc (&newP->frch_obstack);
+      newP->frch_frag_now->fr_type = rs_fill;
+
+      newP->frch_root = newP->frch_last = newP->frch_frag_now;
 
       *lastPP = newP;
       newP->frch_next = frcP;	/* perhaps NULL */
@@ -278,37 +302,9 @@ subseg_set_rest (seg, subseg)
    * Here with frcP pointing to the frchainS for subseg.
    */
   frchain_now = frcP;
-  /*
-   * Make a fresh frag for the subsegment.
-   */
-  /* We expect this to happen on a correct boundary since it was
-     proceeded by a obstack_done(). */
-  tmp = obstack_alignment_mask (&frags);	/* JF disable alignment */
-  obstack_alignment_mask (&frags) = 0;
-  frag_now = (fragS *) obstack_alloc (&frags, SIZEOF_STRUCT_FRAG);
-  memset (frag_now, 0, SIZEOF_STRUCT_FRAG);
-  obstack_alignment_mask (&frags) = tmp;
-  /* But we want any more chars to come immediately after the
-     structure we just made. */
-  new_fragP = frag_now;
-  new_fragP->fr_next = NULL;
-  /*
-   * Append new frag to current frchain.
-   */
-  former_last_fragP = frcP->frch_last;
-  if (former_last_fragP)
-    {
-      know (former_last_fragP->fr_next == NULL);
-      know (frchain_now->frch_root);
-      former_last_fragP->fr_next = new_fragP;
-    }
-  else
-    {
-      frcP->frch_root = new_fragP;
-    }
-  frcP->frch_last = new_fragP;
+  frag_now = frcP->frch_frag_now;
 
-  mri_common_symbol = NULL;
+  assert (frchain_now->frch_last == frag_now);
 }
 
 /*
@@ -379,7 +375,10 @@ subseg_set (seg, subseg)	/* begin assembly for a new sub-segment */
      register subsegT subseg;
 {
 #ifndef MANY_SEGMENTS
-  know (seg == SEG_DATA || seg == SEG_TEXT || seg == SEG_BSS);
+  know (seg == SEG_DATA
+	|| seg == SEG_TEXT
+	|| seg == SEG_BSS
+	|| seg == SEG_ABSOLUTE);
 #endif
 
   if (seg != now_seg || subseg != now_subseg)
-- 
cgit v1.1