From fcc4da3e5227f64b57e5e7ac497df28229b88f7d Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 5 Dec 2014 12:17:15 +0200 Subject: [PATCH] Reduce memory footprint of struct bidi_it by a factor of 5. 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 | 18 ++++++++++++++ src/bidi.c | 64 ++++++++++++++++++++++++++---------------------- src/dispextern.h | 19 +++++++------- 3 files changed, 63 insertions(+), 38 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 2f64a9758bc..82aabb389a3 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,21 @@ +2014-12-05 Eli Zaretskii + + * 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 * eval.c (backtrace_eval_unrewind): Rewind also the excursions. diff --git a/src/bidi.c b/src/bidi.c index a0bcf528e12..cc70d08f01e 100644 --- a/src/bidi.c +++ b/src/bidi.c @@ -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) diff --git a/src/dispextern.h b/src/dispextern.h index 0ee5fd62f7d..5510a1f50c1 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -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. */ -- 2.39.2