]> git.eshelyaron.com Git - emacs.git/commitdiff
Reduce memory footprint of struct bidi_it by a factor of 5.
authorEli Zaretskii <eliz@gnu.org>
Fri, 5 Dec 2014 10:17:15 +0000 (12:17 +0200)
committerEli Zaretskii <eliz@gnu.org>
Fri, 5 Dec 2014 10:17:15 +0000 (12:17 +0200)
 src/dispextern.h (enum bidi_dir_t): Force NEUTRAL_DIR to be zero.
 (struct bidi_stack): Reduce size by using bit fields and by
 packing sos, override, and isolate_status into a single 8-bit
 byte called 'flags'.
 src/bidi.c (ISOLATE_STATUS, OVERRIDE): New macros.
 (bidi_push_embedding_level): Construct flags from individual
 bits.  Adapt to changes in prev_for_neutral and next_for_neutral
 members.
 (bidi_pop_embedding_level): Use ISOLATE_STATUS.  Extract 'sos'
 from flags.  Adapt to changes in prev_for_neutral,
 next_for_neutral, and last_strong members.
 (bidi_line_init): Initialize flags to zero.
 (bidi_resolve_explicit, bidi_resolve_weak, bidi_resolve_brackets)
 (bidi_resolve_neutral): Use ISOLATE_STATUS and OVERRIDE.

src/ChangeLog
src/bidi.c
src/dispextern.h

index 2f64a9758bc1ba9d8ad0396c6bf844971785711b..82aabb389a3dd4660f91a81d08f23c3b56337408 100644 (file)
@@ -1,3 +1,21 @@
+2014-12-05  Eli Zaretskii  <eliz@gnu.org>
+
+       * dispextern.h (enum bidi_dir_t): Force NEUTRAL_DIR to be zero.
+       (struct bidi_stack): Reduce size by using bit fields and by
+       packing sos, override, and isolate_status into a single 8-bit
+       byte called 'flags'.
+
+       * bidi.c (ISOLATE_STATUS, OVERRIDE): New macros.
+       (bidi_push_embedding_level): Construct flags from individual
+       bits.  Adapt to changes in prev_for_neutral and next_for_neutral
+       members.
+       (bidi_pop_embedding_level): Use ISOLATE_STATUS.  Extract 'sos'
+       from flags.  Adapt to changes in prev_for_neutral,
+       next_for_neutral, and last_strong members.
+       (bidi_line_init): Initialize flags to zero.
+       (bidi_resolve_explicit, bidi_resolve_weak, bidi_resolve_brackets)
+       (bidi_resolve_neutral): Use ISOLATE_STATUS and OVERRIDE.
+
 2014-12-04  Stefan Monnier  <monnier@iro.umontreal.ca>
 
        * eval.c (backtrace_eval_unrewind): Rewind also the excursions.
index a0bcf528e128047b037a7fcb46854d4e53cd0782..cc70d08f01e93f61b4de320cd7f66f89790b1be2 100644 (file)
@@ -433,6 +433,9 @@ bidi_set_sos_type (struct bidi_it *bidi_it, int level_before, int level_after)
     = bidi_it->next_for_neutral.orig_type = UNKNOWN_BT;
 }
 
+#define ISOLATE_STATUS(BIDI_IT, IDX)  ((BIDI_IT)->level_stack[IDX].flags & 1)
+#define OVERRIDE(BIDI_IT, IDX)  (((BIDI_IT)->level_stack[IDX].flags >> 1) & 3)
+
 /* Push the current embedding level and override status; reset the
    current level to LEVEL and the current override status to OVERRIDE.  */
 static void
@@ -447,14 +450,14 @@ bidi_push_embedding_level (struct bidi_it *bidi_it,
   st = &bidi_it->level_stack[bidi_it->stack_idx];
   eassert (level <= (1 << 7));
   st->level = level;
-  st->override = override;
-  st->isolate_status = isolate_status;
+  st->flags = (((override & 3) << 1) | (isolate_status != 0));
   if (isolate_status)
     {
-      st->last_strong = bidi_it->last_strong;
-      st->prev_for_neutral = bidi_it->prev_for_neutral;
-      st->next_for_neutral = bidi_it->next_for_neutral;
-      st->sos = bidi_it->sos;
+      st->last_strong_type = bidi_it->last_strong.type;
+      st->prev_for_neutral_type = bidi_it->prev_for_neutral.type;
+      st->next_for_neutral_type = bidi_it->next_for_neutral.type;
+      st->next_for_neutral_pos = bidi_it->next_for_neutral.charpos;
+      st->flags |= ((bidi_it->sos == L2R ? 0 : 1) << 3);
     }
   /* We've got a new isolating sequence, compute the directional type
      of sos and initialize per-sequence variables (UAX#9, clause X10).  */
@@ -473,8 +476,7 @@ bidi_pop_embedding_level (struct bidi_it *bidi_it)
      and PDIs (X6a, 2nd bullet).  */
   if (bidi_it->stack_idx > 0)
     {
-      bool isolate_status
-       = bidi_it->level_stack[bidi_it->stack_idx].isolate_status;
+      bool isolate_status = ISOLATE_STATUS (bidi_it, bidi_it->stack_idx);
       int old_level = bidi_it->level_stack[bidi_it->stack_idx].level;
 
       struct bidi_stack st;
@@ -482,6 +484,7 @@ bidi_pop_embedding_level (struct bidi_it *bidi_it)
       st = bidi_it->level_stack[bidi_it->stack_idx];
       if (isolate_status)
        {
+         bidi_dir_t sos = ((st.flags >> 3) & 1);
          /* PREV is used in W1 for resolving WEAK_NSM.  By the time
             we get to an NSM, we must have gotten past at least one
             character: the PDI that ends the isolate from which we
@@ -490,10 +493,11 @@ bidi_pop_embedding_level (struct bidi_it *bidi_it)
             UNKNOWN_BT to be able to catch any blunders in this
             logic.  */
          bidi_it->prev.orig_type = bidi_it->prev.type = UNKNOWN_BT;
-         bidi_it->last_strong = st.last_strong;
-         bidi_it->prev_for_neutral = st.prev_for_neutral;
-         bidi_it->next_for_neutral = st.next_for_neutral;
-         bidi_it->sos = st.sos;
+         bidi_it->last_strong.type = st.last_strong_type;
+         bidi_it->prev_for_neutral.type = st.prev_for_neutral_type;
+         bidi_it->next_for_neutral.type = st.next_for_neutral_type;
+         bidi_it->next_for_neutral.charpos = st.next_for_neutral_pos;
+         bidi_it->sos = (sos == 0 ? L2R : R2L);
        }
       else
        bidi_set_sos_type (bidi_it, old_level,
@@ -1104,8 +1108,7 @@ bidi_line_init (struct bidi_it *bidi_it)
   bidi_it->scan_dir = 1; /* FIXME: do we need to have control on this? */
   bidi_it->stack_idx = 0;
   bidi_it->resolved_level = bidi_it->level_stack[0].level;
-  bidi_it->level_stack[0].override = NEUTRAL_DIR; /* X1 */
-  bidi_it->level_stack[0].isolate_status = false; /* X1 */
+  bidi_it->level_stack[0].flags = 0; /* NEUTRAL_DIR, false per X1 */
   bidi_it->invalid_levels = 0;
   bidi_it->isolate_level = 0;   /* X1 */
   bidi_it->invalid_isolates = 0; /* X1 */
@@ -1858,8 +1861,8 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
     prev_type = NEUTRAL_B;
 
   current_level = bidi_it->level_stack[bidi_it->stack_idx].level; /* X1 */
-  override = bidi_it->level_stack[bidi_it->stack_idx].override;
-  isolate_status = bidi_it->level_stack[bidi_it->stack_idx].isolate_status;
+  isolate_status = ISOLATE_STATUS (bidi_it, bidi_it->stack_idx);
+  override = OVERRIDE (bidi_it, bidi_it->stack_idx);
   new_level = current_level;
 
   if (bidi_it->charpos >= (string_p ? bidi_it->string.schars : ZV))
@@ -2033,7 +2036,7 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
       else if (bidi_it->isolate_level > 0)
        {
          bidi_it->invalid_levels = 0;
-         while (!bidi_it->level_stack[bidi_it->stack_idx].isolate_status)
+         while (!ISOLATE_STATUS (bidi_it, bidi_it->stack_idx))
            bidi_pop_embedding_level (bidi_it);
          eassert (bidi_it->stack_idx > 0);
          new_level = bidi_pop_embedding_level (bidi_it);
@@ -2041,12 +2044,15 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
        }
       bidi_it->resolved_level = new_level;
       /* Unicode 8.0 correction.  */
-      if (bidi_it->level_stack[bidi_it->stack_idx].override == L2R)
-       bidi_it->type_after_wn = STRONG_L;
-      else if (bidi_it->level_stack[bidi_it->stack_idx].override == R2L)
-       bidi_it->type_after_wn = STRONG_R;
-      else
-       bidi_it->type_after_wn = type;
+      {
+       bidi_dir_t stack_override = OVERRIDE (bidi_it, bidi_it->stack_idx);
+       if (stack_override == L2R)
+         bidi_it->type_after_wn = STRONG_L;
+       else if (stack_override == R2L)
+         bidi_it->type_after_wn = STRONG_R;
+       else
+         bidi_it->type_after_wn = type;
+      }
       break;
     case PDF:  /* X7 */
       bidi_it->type_after_wn = type;
@@ -2089,7 +2095,7 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
        ? bidi_it->string.schars : ZV);
 
   type = bidi_it->type;
-  override = bidi_it->level_stack[bidi_it->stack_idx].override;
+  override = OVERRIDE (bidi_it, bidi_it->stack_idx);
 
   eassert (!(type == UNKNOWN_BT
             || type == LRE
@@ -2557,9 +2563,9 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
          /* Skip level runs excluded from this isolating run sequence.  */
          new_sidx = bidi_it->stack_idx;
          if (bidi_it->level_stack[new_sidx].level > current_level
-             && (bidi_it->level_stack[new_sidx].isolate_status
+             && (ISOLATE_STATUS (bidi_it, new_sidx)
                  || (new_sidx > old_sidx + 1
-                     && bidi_it->level_stack[new_sidx - 1].isolate_status)))
+                     && ISOLATE_STATUS (bidi_it, new_sidx - 1))))
            {
              while (bidi_it->level_stack[bidi_it->stack_idx].level
                     > current_level)
@@ -2729,7 +2735,7 @@ bidi_resolve_brackets (struct bidi_it *bidi_it)
         the prev_for_neutral and next_for_neutral information, so
         that it will be picked up when we advance to that next run.  */
       if (bidi_it->level_stack[bidi_it->stack_idx].level > prev_level
-         && bidi_it->level_stack[bidi_it->stack_idx].isolate_status)
+         && ISOLATE_STATUS (bidi_it, bidi_it->stack_idx))
        {
          bidi_record_type_for_neutral (&prev_for_neutral, prev_level, 0);
          bidi_record_type_for_neutral (&next_for_neutral, prev_level, 1);
@@ -2919,14 +2925,14 @@ bidi_resolve_neutral (struct bidi_it *bidi_it)
            /* Skip level runs excluded from this isolating run sequence.  */
            new_sidx = bidi_it->stack_idx;
            if (bidi_it->level_stack[new_sidx].level > current_level
-               && (bidi_it->level_stack[new_sidx].isolate_status
+               && (ISOLATE_STATUS (bidi_it, new_sidx)
                    /* This is for when we have an isolate initiator
                       immediately followed by an embedding or
                       override initiator, in which case we get the
                       level stack pushed twice by the single call to
                       bidi_resolve_weak above.  */
                    || (new_sidx > old_sidx + 1
-                       && bidi_it->level_stack[new_sidx - 1].isolate_status)))
+                       && ISOLATE_STATUS (bidi_it, new_sidx - 1))))
              {
                while (bidi_it->level_stack[bidi_it->stack_idx].level
                       > current_level)
index 0ee5fd62f7de530c697371d10c7ba7e8bc944f6f..5510a1f50c16ebaf6d1354801754f0db2344ccf4 100644 (file)
@@ -1908,7 +1908,7 @@ typedef enum {
 } bidi_bracket_type_t;
 
 /* The basic directionality data type.  */
-typedef enum { NEUTRAL_DIR, L2R, R2L } bidi_dir_t;
+typedef enum { NEUTRAL_DIR = 0, L2R, R2L } bidi_dir_t;
 
 /* Data type for storing information about characters we need to
    remember.  */
@@ -1920,15 +1920,16 @@ struct bidi_saved_info {
 
 /* Data type for keeping track of information about saved embedding
    levels, override status, isolate status, and isolating sequence
-   runs.  */
+   runs.  This should be as tightly packed as possible, because there
+   are 127 such entries in each iterator state, and so the size of
+   cache is directly affected by the size of this struct.  */
 struct bidi_stack {
-  struct bidi_saved_info last_strong;
-  struct bidi_saved_info next_for_neutral;
-  struct bidi_saved_info prev_for_neutral;
-  unsigned level : 7;
-  bool_bf isolate_status : 1;
-  unsigned override : 2;
-  unsigned sos : 2;
+  ptrdiff_t next_for_neutral_pos;
+  unsigned next_for_neutral_type : 3;
+  unsigned last_strong_type : 3;
+  unsigned prev_for_neutral_type : 3;
+  unsigned char level;
+  unsigned char flags;         /* sos, override, isolate_status */
 };
 
 /* Data type for storing information about a string being iterated on.  */