diff options
| author | Eli Zaretskii | 2014-12-05 12:17:15 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2014-12-05 12:17:15 +0200 |
| commit | fcc4da3e5227f64b57e5e7ac497df28229b88f7d (patch) | |
| tree | ae2dbadb71fb2552277410415a5753c8edf9a2ac | |
| parent | 96e6fd3c155b1851e0acd477789535a45b8d3187 (diff) | |
| download | emacs-fcc4da3e5227f64b57e5e7ac497df28229b88f7d.tar.gz emacs-fcc4da3e5227f64b57e5e7ac497df28229b88f7d.zip | |
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.
| -rw-r--r-- | src/ChangeLog | 18 | ||||
| -rw-r--r-- | src/bidi.c | 64 | ||||
| -rw-r--r-- | 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 @@ | |||
| 1 | 2014-12-05 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * dispextern.h (enum bidi_dir_t): Force NEUTRAL_DIR to be zero. | ||
| 4 | (struct bidi_stack): Reduce size by using bit fields and by | ||
| 5 | packing sos, override, and isolate_status into a single 8-bit | ||
| 6 | byte called 'flags'. | ||
| 7 | |||
| 8 | * bidi.c (ISOLATE_STATUS, OVERRIDE): New macros. | ||
| 9 | (bidi_push_embedding_level): Construct flags from individual | ||
| 10 | bits. Adapt to changes in prev_for_neutral and next_for_neutral | ||
| 11 | members. | ||
| 12 | (bidi_pop_embedding_level): Use ISOLATE_STATUS. Extract 'sos' | ||
| 13 | from flags. Adapt to changes in prev_for_neutral, | ||
| 14 | next_for_neutral, and last_strong members. | ||
| 15 | (bidi_line_init): Initialize flags to zero. | ||
| 16 | (bidi_resolve_explicit, bidi_resolve_weak, bidi_resolve_brackets) | ||
| 17 | (bidi_resolve_neutral): Use ISOLATE_STATUS and OVERRIDE. | ||
| 18 | |||
| 1 | 2014-12-04 Stefan Monnier <monnier@iro.umontreal.ca> | 19 | 2014-12-04 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 20 | ||
| 3 | * eval.c (backtrace_eval_unrewind): Rewind also the excursions. | 21 | * 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) | |||
| 433 | = bidi_it->next_for_neutral.orig_type = UNKNOWN_BT; | 433 | = bidi_it->next_for_neutral.orig_type = UNKNOWN_BT; |
| 434 | } | 434 | } |
| 435 | 435 | ||
| 436 | #define ISOLATE_STATUS(BIDI_IT, IDX) ((BIDI_IT)->level_stack[IDX].flags & 1) | ||
| 437 | #define OVERRIDE(BIDI_IT, IDX) (((BIDI_IT)->level_stack[IDX].flags >> 1) & 3) | ||
| 438 | |||
| 436 | /* Push the current embedding level and override status; reset the | 439 | /* Push the current embedding level and override status; reset the |
| 437 | current level to LEVEL and the current override status to OVERRIDE. */ | 440 | current level to LEVEL and the current override status to OVERRIDE. */ |
| 438 | static void | 441 | static void |
| @@ -447,14 +450,14 @@ bidi_push_embedding_level (struct bidi_it *bidi_it, | |||
| 447 | st = &bidi_it->level_stack[bidi_it->stack_idx]; | 450 | st = &bidi_it->level_stack[bidi_it->stack_idx]; |
| 448 | eassert (level <= (1 << 7)); | 451 | eassert (level <= (1 << 7)); |
| 449 | st->level = level; | 452 | st->level = level; |
| 450 | st->override = override; | 453 | st->flags = (((override & 3) << 1) | (isolate_status != 0)); |
| 451 | st->isolate_status = isolate_status; | ||
| 452 | if (isolate_status) | 454 | if (isolate_status) |
| 453 | { | 455 | { |
| 454 | st->last_strong = bidi_it->last_strong; | 456 | st->last_strong_type = bidi_it->last_strong.type; |
| 455 | st->prev_for_neutral = bidi_it->prev_for_neutral; | 457 | st->prev_for_neutral_type = bidi_it->prev_for_neutral.type; |
| 456 | st->next_for_neutral = bidi_it->next_for_neutral; | 458 | st->next_for_neutral_type = bidi_it->next_for_neutral.type; |
| 457 | st->sos = bidi_it->sos; | 459 | st->next_for_neutral_pos = bidi_it->next_for_neutral.charpos; |
| 460 | st->flags |= ((bidi_it->sos == L2R ? 0 : 1) << 3); | ||
| 458 | } | 461 | } |
| 459 | /* We've got a new isolating sequence, compute the directional type | 462 | /* We've got a new isolating sequence, compute the directional type |
| 460 | of sos and initialize per-sequence variables (UAX#9, clause X10). */ | 463 | of sos and initialize per-sequence variables (UAX#9, clause X10). */ |
| @@ -473,8 +476,7 @@ bidi_pop_embedding_level (struct bidi_it *bidi_it) | |||
| 473 | and PDIs (X6a, 2nd bullet). */ | 476 | and PDIs (X6a, 2nd bullet). */ |
| 474 | if (bidi_it->stack_idx > 0) | 477 | if (bidi_it->stack_idx > 0) |
| 475 | { | 478 | { |
| 476 | bool isolate_status | 479 | bool isolate_status = ISOLATE_STATUS (bidi_it, bidi_it->stack_idx); |
| 477 | = bidi_it->level_stack[bidi_it->stack_idx].isolate_status; | ||
| 478 | int old_level = bidi_it->level_stack[bidi_it->stack_idx].level; | 480 | int old_level = bidi_it->level_stack[bidi_it->stack_idx].level; |
| 479 | 481 | ||
| 480 | struct bidi_stack st; | 482 | struct bidi_stack st; |
| @@ -482,6 +484,7 @@ bidi_pop_embedding_level (struct bidi_it *bidi_it) | |||
| 482 | st = bidi_it->level_stack[bidi_it->stack_idx]; | 484 | st = bidi_it->level_stack[bidi_it->stack_idx]; |
| 483 | if (isolate_status) | 485 | if (isolate_status) |
| 484 | { | 486 | { |
| 487 | bidi_dir_t sos = ((st.flags >> 3) & 1); | ||
| 485 | /* PREV is used in W1 for resolving WEAK_NSM. By the time | 488 | /* PREV is used in W1 for resolving WEAK_NSM. By the time |
| 486 | we get to an NSM, we must have gotten past at least one | 489 | we get to an NSM, we must have gotten past at least one |
| 487 | character: the PDI that ends the isolate from which we | 490 | character: the PDI that ends the isolate from which we |
| @@ -490,10 +493,11 @@ bidi_pop_embedding_level (struct bidi_it *bidi_it) | |||
| 490 | UNKNOWN_BT to be able to catch any blunders in this | 493 | UNKNOWN_BT to be able to catch any blunders in this |
| 491 | logic. */ | 494 | logic. */ |
| 492 | bidi_it->prev.orig_type = bidi_it->prev.type = UNKNOWN_BT; | 495 | bidi_it->prev.orig_type = bidi_it->prev.type = UNKNOWN_BT; |
| 493 | bidi_it->last_strong = st.last_strong; | 496 | bidi_it->last_strong.type = st.last_strong_type; |
| 494 | bidi_it->prev_for_neutral = st.prev_for_neutral; | 497 | bidi_it->prev_for_neutral.type = st.prev_for_neutral_type; |
| 495 | bidi_it->next_for_neutral = st.next_for_neutral; | 498 | bidi_it->next_for_neutral.type = st.next_for_neutral_type; |
| 496 | bidi_it->sos = st.sos; | 499 | bidi_it->next_for_neutral.charpos = st.next_for_neutral_pos; |
| 500 | bidi_it->sos = (sos == 0 ? L2R : R2L); | ||
| 497 | } | 501 | } |
| 498 | else | 502 | else |
| 499 | bidi_set_sos_type (bidi_it, old_level, | 503 | bidi_set_sos_type (bidi_it, old_level, |
| @@ -1104,8 +1108,7 @@ bidi_line_init (struct bidi_it *bidi_it) | |||
| 1104 | bidi_it->scan_dir = 1; /* FIXME: do we need to have control on this? */ | 1108 | bidi_it->scan_dir = 1; /* FIXME: do we need to have control on this? */ |
| 1105 | bidi_it->stack_idx = 0; | 1109 | bidi_it->stack_idx = 0; |
| 1106 | bidi_it->resolved_level = bidi_it->level_stack[0].level; | 1110 | bidi_it->resolved_level = bidi_it->level_stack[0].level; |
| 1107 | bidi_it->level_stack[0].override = NEUTRAL_DIR; /* X1 */ | 1111 | bidi_it->level_stack[0].flags = 0; /* NEUTRAL_DIR, false per X1 */ |
| 1108 | bidi_it->level_stack[0].isolate_status = false; /* X1 */ | ||
| 1109 | bidi_it->invalid_levels = 0; | 1112 | bidi_it->invalid_levels = 0; |
| 1110 | bidi_it->isolate_level = 0; /* X1 */ | 1113 | bidi_it->isolate_level = 0; /* X1 */ |
| 1111 | bidi_it->invalid_isolates = 0; /* X1 */ | 1114 | bidi_it->invalid_isolates = 0; /* X1 */ |
| @@ -1858,8 +1861,8 @@ bidi_resolve_explicit (struct bidi_it *bidi_it) | |||
| 1858 | prev_type = NEUTRAL_B; | 1861 | prev_type = NEUTRAL_B; |
| 1859 | 1862 | ||
| 1860 | current_level = bidi_it->level_stack[bidi_it->stack_idx].level; /* X1 */ | 1863 | current_level = bidi_it->level_stack[bidi_it->stack_idx].level; /* X1 */ |
| 1861 | override = bidi_it->level_stack[bidi_it->stack_idx].override; | 1864 | isolate_status = ISOLATE_STATUS (bidi_it, bidi_it->stack_idx); |
| 1862 | isolate_status = bidi_it->level_stack[bidi_it->stack_idx].isolate_status; | 1865 | override = OVERRIDE (bidi_it, bidi_it->stack_idx); |
| 1863 | new_level = current_level; | 1866 | new_level = current_level; |
| 1864 | 1867 | ||
| 1865 | if (bidi_it->charpos >= (string_p ? bidi_it->string.schars : ZV)) | 1868 | if (bidi_it->charpos >= (string_p ? bidi_it->string.schars : ZV)) |
| @@ -2033,7 +2036,7 @@ bidi_resolve_explicit (struct bidi_it *bidi_it) | |||
| 2033 | else if (bidi_it->isolate_level > 0) | 2036 | else if (bidi_it->isolate_level > 0) |
| 2034 | { | 2037 | { |
| 2035 | bidi_it->invalid_levels = 0; | 2038 | bidi_it->invalid_levels = 0; |
| 2036 | while (!bidi_it->level_stack[bidi_it->stack_idx].isolate_status) | 2039 | while (!ISOLATE_STATUS (bidi_it, bidi_it->stack_idx)) |
| 2037 | bidi_pop_embedding_level (bidi_it); | 2040 | bidi_pop_embedding_level (bidi_it); |
| 2038 | eassert (bidi_it->stack_idx > 0); | 2041 | eassert (bidi_it->stack_idx > 0); |
| 2039 | new_level = bidi_pop_embedding_level (bidi_it); | 2042 | new_level = bidi_pop_embedding_level (bidi_it); |
| @@ -2041,12 +2044,15 @@ bidi_resolve_explicit (struct bidi_it *bidi_it) | |||
| 2041 | } | 2044 | } |
| 2042 | bidi_it->resolved_level = new_level; | 2045 | bidi_it->resolved_level = new_level; |
| 2043 | /* Unicode 8.0 correction. */ | 2046 | /* Unicode 8.0 correction. */ |
| 2044 | if (bidi_it->level_stack[bidi_it->stack_idx].override == L2R) | 2047 | { |
| 2045 | bidi_it->type_after_wn = STRONG_L; | 2048 | bidi_dir_t stack_override = OVERRIDE (bidi_it, bidi_it->stack_idx); |
| 2046 | else if (bidi_it->level_stack[bidi_it->stack_idx].override == R2L) | 2049 | if (stack_override == L2R) |
| 2047 | bidi_it->type_after_wn = STRONG_R; | 2050 | bidi_it->type_after_wn = STRONG_L; |
| 2048 | else | 2051 | else if (stack_override == R2L) |
| 2049 | bidi_it->type_after_wn = type; | 2052 | bidi_it->type_after_wn = STRONG_R; |
| 2053 | else | ||
| 2054 | bidi_it->type_after_wn = type; | ||
| 2055 | } | ||
| 2050 | break; | 2056 | break; |
| 2051 | case PDF: /* X7 */ | 2057 | case PDF: /* X7 */ |
| 2052 | bidi_it->type_after_wn = type; | 2058 | bidi_it->type_after_wn = type; |
| @@ -2089,7 +2095,7 @@ bidi_resolve_weak (struct bidi_it *bidi_it) | |||
| 2089 | ? bidi_it->string.schars : ZV); | 2095 | ? bidi_it->string.schars : ZV); |
| 2090 | 2096 | ||
| 2091 | type = bidi_it->type; | 2097 | type = bidi_it->type; |
| 2092 | override = bidi_it->level_stack[bidi_it->stack_idx].override; | 2098 | override = OVERRIDE (bidi_it, bidi_it->stack_idx); |
| 2093 | 2099 | ||
| 2094 | eassert (!(type == UNKNOWN_BT | 2100 | eassert (!(type == UNKNOWN_BT |
| 2095 | || type == LRE | 2101 | || type == LRE |
| @@ -2557,9 +2563,9 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it) | |||
| 2557 | /* Skip level runs excluded from this isolating run sequence. */ | 2563 | /* Skip level runs excluded from this isolating run sequence. */ |
| 2558 | new_sidx = bidi_it->stack_idx; | 2564 | new_sidx = bidi_it->stack_idx; |
| 2559 | if (bidi_it->level_stack[new_sidx].level > current_level | 2565 | if (bidi_it->level_stack[new_sidx].level > current_level |
| 2560 | && (bidi_it->level_stack[new_sidx].isolate_status | 2566 | && (ISOLATE_STATUS (bidi_it, new_sidx) |
| 2561 | || (new_sidx > old_sidx + 1 | 2567 | || (new_sidx > old_sidx + 1 |
| 2562 | && bidi_it->level_stack[new_sidx - 1].isolate_status))) | 2568 | && ISOLATE_STATUS (bidi_it, new_sidx - 1)))) |
| 2563 | { | 2569 | { |
| 2564 | while (bidi_it->level_stack[bidi_it->stack_idx].level | 2570 | while (bidi_it->level_stack[bidi_it->stack_idx].level |
| 2565 | > current_level) | 2571 | > current_level) |
| @@ -2729,7 +2735,7 @@ bidi_resolve_brackets (struct bidi_it *bidi_it) | |||
| 2729 | the prev_for_neutral and next_for_neutral information, so | 2735 | the prev_for_neutral and next_for_neutral information, so |
| 2730 | that it will be picked up when we advance to that next run. */ | 2736 | that it will be picked up when we advance to that next run. */ |
| 2731 | if (bidi_it->level_stack[bidi_it->stack_idx].level > prev_level | 2737 | if (bidi_it->level_stack[bidi_it->stack_idx].level > prev_level |
| 2732 | && bidi_it->level_stack[bidi_it->stack_idx].isolate_status) | 2738 | && ISOLATE_STATUS (bidi_it, bidi_it->stack_idx)) |
| 2733 | { | 2739 | { |
| 2734 | bidi_record_type_for_neutral (&prev_for_neutral, prev_level, 0); | 2740 | bidi_record_type_for_neutral (&prev_for_neutral, prev_level, 0); |
| 2735 | bidi_record_type_for_neutral (&next_for_neutral, prev_level, 1); | 2741 | bidi_record_type_for_neutral (&next_for_neutral, prev_level, 1); |
| @@ -2919,14 +2925,14 @@ bidi_resolve_neutral (struct bidi_it *bidi_it) | |||
| 2919 | /* Skip level runs excluded from this isolating run sequence. */ | 2925 | /* Skip level runs excluded from this isolating run sequence. */ |
| 2920 | new_sidx = bidi_it->stack_idx; | 2926 | new_sidx = bidi_it->stack_idx; |
| 2921 | if (bidi_it->level_stack[new_sidx].level > current_level | 2927 | if (bidi_it->level_stack[new_sidx].level > current_level |
| 2922 | && (bidi_it->level_stack[new_sidx].isolate_status | 2928 | && (ISOLATE_STATUS (bidi_it, new_sidx) |
| 2923 | /* This is for when we have an isolate initiator | 2929 | /* This is for when we have an isolate initiator |
| 2924 | immediately followed by an embedding or | 2930 | immediately followed by an embedding or |
| 2925 | override initiator, in which case we get the | 2931 | override initiator, in which case we get the |
| 2926 | level stack pushed twice by the single call to | 2932 | level stack pushed twice by the single call to |
| 2927 | bidi_resolve_weak above. */ | 2933 | bidi_resolve_weak above. */ |
| 2928 | || (new_sidx > old_sidx + 1 | 2934 | || (new_sidx > old_sidx + 1 |
| 2929 | && bidi_it->level_stack[new_sidx - 1].isolate_status))) | 2935 | && ISOLATE_STATUS (bidi_it, new_sidx - 1)))) |
| 2930 | { | 2936 | { |
| 2931 | while (bidi_it->level_stack[bidi_it->stack_idx].level | 2937 | while (bidi_it->level_stack[bidi_it->stack_idx].level |
| 2932 | > current_level) | 2938 | > 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 { | |||
| 1908 | } bidi_bracket_type_t; | 1908 | } bidi_bracket_type_t; |
| 1909 | 1909 | ||
| 1910 | /* The basic directionality data type. */ | 1910 | /* The basic directionality data type. */ |
| 1911 | typedef enum { NEUTRAL_DIR, L2R, R2L } bidi_dir_t; | 1911 | typedef enum { NEUTRAL_DIR = 0, L2R, R2L } bidi_dir_t; |
| 1912 | 1912 | ||
| 1913 | /* Data type for storing information about characters we need to | 1913 | /* Data type for storing information about characters we need to |
| 1914 | remember. */ | 1914 | remember. */ |
| @@ -1920,15 +1920,16 @@ struct bidi_saved_info { | |||
| 1920 | 1920 | ||
| 1921 | /* Data type for keeping track of information about saved embedding | 1921 | /* Data type for keeping track of information about saved embedding |
| 1922 | levels, override status, isolate status, and isolating sequence | 1922 | levels, override status, isolate status, and isolating sequence |
| 1923 | runs. */ | 1923 | runs. This should be as tightly packed as possible, because there |
| 1924 | are 127 such entries in each iterator state, and so the size of | ||
| 1925 | cache is directly affected by the size of this struct. */ | ||
| 1924 | struct bidi_stack { | 1926 | struct bidi_stack { |
| 1925 | struct bidi_saved_info last_strong; | 1927 | ptrdiff_t next_for_neutral_pos; |
| 1926 | struct bidi_saved_info next_for_neutral; | 1928 | unsigned next_for_neutral_type : 3; |
| 1927 | struct bidi_saved_info prev_for_neutral; | 1929 | unsigned last_strong_type : 3; |
| 1928 | unsigned level : 7; | 1930 | unsigned prev_for_neutral_type : 3; |
| 1929 | bool_bf isolate_status : 1; | 1931 | unsigned char level; |
| 1930 | unsigned override : 2; | 1932 | unsigned char flags; /* sos, override, isolate_status */ |
| 1931 | unsigned sos : 2; | ||
| 1932 | }; | 1933 | }; |
| 1933 | 1934 | ||
| 1934 | /* Data type for storing information about a string being iterated on. */ | 1935 | /* Data type for storing information about a string being iterated on. */ |