From 35928349678bc6ed8f621fe7d4da6a9a3fb3579d Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 5 Aug 2011 13:48:37 +0300 Subject: [PATCH] Fix bug #9221 with resource allocation under word-wrap. Add diagnostic facility for monitoring memory allocated for cache shelving. src/xdisp.c (display_line): Release buffer allocated for shelved bidi cache. (Bug#9221) src/bidi.c (bidi_shelve_cache, bidi_unshelve_cache): Track total amount allocated this far in `bidi_cache_total_alloc'. (bidi_unshelve_cache): Accept an additional argument JUST_FREE; if non-zero, only free the data buffer without restoring the cache contents. All callers changed. src/dispextern.h (bidi_unshelve_cache): Update prototype. src/xdisp.c (SAVE_IT, pos_visible_p, move_it_in_display_line_to) (move_it_in_display_line, move_it_to) (move_it_vertically_backward, move_it_by_lines): Replace the call to xfree to an equivalent call to bidi_unshelve_cache. (move_it_in_display_line_to): Fix logic of returning MOVE_POS_MATCH_OR_ZV in the bidi case. --- src/ChangeLog | 20 +++++++++++++++ src/bidi.c | 76 +++++++++++++++++++++++++++++++++++++------------------- src/dispextern.h | 2 +- src/dispnew.c | 2 +- src/indent.c | 2 +- src/window.c | 18 +++++++------- src/xdisp.c | 53 ++++++++++++++++++++------------------- 7 files changed, 110 insertions(+), 63 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 8aa1237f693..481e5e1ce02 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,23 @@ +2011-08-05 Eli Zaretskii + + *xdisp.c (display_line): Release buffer allocated for shelved bidi + cache. (Bug#9221) + + * bidi.c (bidi_shelve_cache, bidi_unshelve_cache): Track total + amount allocated this far in `bidi_cache_total_alloc'. + (bidi_unshelve_cache): Accept an additional argument JUST_FREE; if + non-zero, only free the data buffer without restoring the cache + contents. All callers changed. + + * dispextern.h (bidi_unshelve_cache): Update prototype. + + * xdisp.c (SAVE_IT, pos_visible_p, move_it_in_display_line_to) + (move_it_in_display_line, move_it_to) + (move_it_vertically_backward, move_it_by_lines): Replace the call + to xfree to an equivalent call to bidi_unshelve_cache. + (move_it_in_display_line_to): Fix logic of returning + MOVE_POS_MATCH_OR_ZV in the bidi case. + 2011-07-24 Eli Zaretskii * xdisp.c (compute_display_string_pos): Fix logic of caching diff --git a/src/bidi.c b/src/bidi.c index 77043d9236f..a2ba60a7baf 100644 --- a/src/bidi.c +++ b/src/bidi.c @@ -609,12 +609,15 @@ bidi_pop_it (struct bidi_it *bidi_it) bidi_cache_last_idx = -1; } +ptrdiff_t bidi_cache_total_alloc; + /* Stash away a copy of the cache and its control variables. */ void * bidi_shelve_cache (void) { unsigned char *databuf; + /* Empty cache. */ if (bidi_cache_idx == 0) return NULL; @@ -623,6 +626,12 @@ bidi_shelve_cache (void) + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp) + sizeof (bidi_cache_start) + sizeof (bidi_cache_last_idx)); + bidi_cache_total_alloc += + sizeof (bidi_cache_idx) + bidi_cache_idx * sizeof (struct bidi_it) + + sizeof (bidi_cache_start_stack) + + sizeof (bidi_cache_sp) + sizeof (bidi_cache_start) + + sizeof (bidi_cache_last_idx); + memcpy (databuf, &bidi_cache_idx, sizeof (bidi_cache_idx)); memcpy (databuf + sizeof (bidi_cache_idx), bidi_cache, bidi_cache_idx * sizeof (struct bidi_it)); @@ -648,7 +657,7 @@ bidi_shelve_cache (void) /* Restore the cache state from a copy stashed away by bidi_shelve_cache. */ void -bidi_unshelve_cache (void *databuf) +bidi_unshelve_cache (void *databuf, int just_free) { unsigned char *p = databuf; @@ -661,30 +670,47 @@ bidi_unshelve_cache (void *databuf) } else { - memcpy (&bidi_cache_idx, p, sizeof (bidi_cache_idx)); - bidi_cache_ensure_space (bidi_cache_idx); - memcpy (bidi_cache, p + sizeof (bidi_cache_idx), - bidi_cache_idx * sizeof (struct bidi_it)); - memcpy (bidi_cache_start_stack, - p + sizeof (bidi_cache_idx) - + bidi_cache_idx * sizeof (struct bidi_it), - sizeof (bidi_cache_start_stack)); - memcpy (&bidi_cache_sp, - p + sizeof (bidi_cache_idx) - + bidi_cache_idx * sizeof (struct bidi_it) - + sizeof (bidi_cache_start_stack), - sizeof (bidi_cache_sp)); - memcpy (&bidi_cache_start, - p + sizeof (bidi_cache_idx) - + bidi_cache_idx * sizeof (struct bidi_it) - + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp), - sizeof (bidi_cache_start)); - memcpy (&bidi_cache_last_idx, - p + sizeof (bidi_cache_idx) - + bidi_cache_idx * sizeof (struct bidi_it) - + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp) - + sizeof (bidi_cache_start), - sizeof (bidi_cache_last_idx)); + if (just_free) + { + ptrdiff_t idx; + + memcpy (&idx, p, sizeof (bidi_cache_idx)); + bidi_cache_total_alloc -= + sizeof (bidi_cache_idx) + idx * sizeof (struct bidi_it) + + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp) + + sizeof (bidi_cache_start) + sizeof (bidi_cache_last_idx); + } + else + { + memcpy (&bidi_cache_idx, p, sizeof (bidi_cache_idx)); + bidi_cache_ensure_space (bidi_cache_idx); + memcpy (bidi_cache, p + sizeof (bidi_cache_idx), + bidi_cache_idx * sizeof (struct bidi_it)); + memcpy (bidi_cache_start_stack, + p + sizeof (bidi_cache_idx) + + bidi_cache_idx * sizeof (struct bidi_it), + sizeof (bidi_cache_start_stack)); + memcpy (&bidi_cache_sp, + p + sizeof (bidi_cache_idx) + + bidi_cache_idx * sizeof (struct bidi_it) + + sizeof (bidi_cache_start_stack), + sizeof (bidi_cache_sp)); + memcpy (&bidi_cache_start, + p + sizeof (bidi_cache_idx) + + bidi_cache_idx * sizeof (struct bidi_it) + + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp), + sizeof (bidi_cache_start)); + memcpy (&bidi_cache_last_idx, + p + sizeof (bidi_cache_idx) + + bidi_cache_idx * sizeof (struct bidi_it) + + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp) + + sizeof (bidi_cache_start), + sizeof (bidi_cache_last_idx)); + bidi_cache_total_alloc -= + sizeof (bidi_cache_idx) + bidi_cache_idx * sizeof (struct bidi_it) + + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp) + + sizeof (bidi_cache_start) + sizeof (bidi_cache_last_idx); + } xfree (p); } diff --git a/src/dispextern.h b/src/dispextern.h index 5bb72ff7600..32b4bbfab24 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -2975,7 +2975,7 @@ extern int bidi_mirror_char (int); extern void bidi_push_it (struct bidi_it *); extern void bidi_pop_it (struct bidi_it *); extern void *bidi_shelve_cache (void); -extern void bidi_unshelve_cache (void *); +extern void bidi_unshelve_cache (void *, int); /* Defined in xdisp.c */ diff --git a/src/dispnew.c b/src/dispnew.c index 69b32a5cd79..64fa5733741 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -5311,7 +5311,7 @@ buffer_posn_from_coords (struct window *w, int *x, int *y, struct display_pos *p argument is ZV to prevent move_it_in_display_line from matching based on buffer positions. */ move_it_in_display_line (&it, ZV, to_x, MOVE_TO_X); - bidi_unshelve_cache (itdata); + bidi_unshelve_cache (itdata, 0); Fset_buffer (old_current_buffer); diff --git a/src/indent.c b/src/indent.c index a73284c6657..3f7b3efe3b8 100644 --- a/src/indent.c +++ b/src/indent.c @@ -2135,7 +2135,7 @@ whether or not it is currently displayed in some window. */) } SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it)); - bidi_unshelve_cache (itdata); + bidi_unshelve_cache (itdata, 0); } if (BUFFERP (old_buffer)) diff --git a/src/window.c b/src/window.c index 094cfcfbda3..d733dea5026 100644 --- a/src/window.c +++ b/src/window.c @@ -1190,7 +1190,7 @@ if it isn't already recorded. */) if (it.current_y < it.last_visible_y) move_it_past_eol (&it); value = make_number (IT_CHARPOS (it)); - bidi_unshelve_cache (itdata); + bidi_unshelve_cache (itdata, 0); if (old_buffer) set_buffer_internal (old_buffer); @@ -4771,7 +4771,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, int whole, int noerror) } start = it.current.pos; - bidi_unshelve_cache (itdata); + bidi_unshelve_cache (itdata, 0); } else if (auto_window_vscroll_p) { @@ -4915,7 +4915,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, int whole, int noerror) } else { - bidi_unshelve_cache (itdata); + bidi_unshelve_cache (itdata, 0); if (noerror) return; else if (n < 0) /* could happen with empty buffers */ @@ -4932,7 +4932,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, int whole, int noerror) w->vscroll = 0; else { - bidi_unshelve_cache (itdata); + bidi_unshelve_cache (itdata, 0); if (noerror) return; else @@ -5081,7 +5081,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, int whole, int noerror) SET_PT_BOTH (charpos, bytepos); } } - bidi_unshelve_cache (itdata); + bidi_unshelve_cache (itdata, 0); } @@ -5508,7 +5508,7 @@ displayed_window_lines (struct window *w) start_display (&it, w, start); move_it_vertically (&it, height); bottom_y = line_bottom_y (&it); - bidi_unshelve_cache (itdata); + bidi_unshelve_cache (itdata, 0); /* rms: On a non-window display, the value of it.vpos at the bottom of the screen @@ -5614,7 +5614,7 @@ and redisplay normally--don't erase and redraw the frame. */) move_it_vertically_backward (&it, window_box_height (w) / 2); charpos = IT_CHARPOS (it); bytepos = IT_BYTEPOS (it); - bidi_unshelve_cache (itdata); + bidi_unshelve_cache (itdata, 0); } else if (iarg < 0) { @@ -5662,7 +5662,7 @@ and redisplay normally--don't erase and redraw the frame. */) } if (h <= 0) { - bidi_unshelve_cache (itdata); + bidi_unshelve_cache (itdata, 0); return Qnil; } @@ -5685,7 +5685,7 @@ and redisplay normally--don't erase and redraw the frame. */) charpos = IT_CHARPOS (it); bytepos = IT_BYTEPOS (it); - bidi_unshelve_cache (itdata); + bidi_unshelve_cache (itdata, 0); } else { diff --git a/src/xdisp.c b/src/xdisp.c index 5f9e80cd11e..77bd4e5ee9a 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -604,7 +604,7 @@ int current_mode_line_height, current_header_line_height; #define SAVE_IT(ITCOPY,ITORIG,CACHE) \ do { \ if (CACHE) \ - xfree (CACHE); \ + bidi_unshelve_cache (CACHE, 1); \ ITCOPY = ITORIG; \ CACHE = bidi_shelve_cache(); \ } while (0) @@ -613,7 +613,7 @@ int current_mode_line_height, current_header_line_height; do { \ if (pITORIG != pITCOPY) \ *(pITORIG) = *(pITCOPY); \ - bidi_unshelve_cache (CACHE); \ + bidi_unshelve_cache (CACHE, 0); \ CACHE = NULL; \ } while (0) @@ -1341,9 +1341,9 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y, *vpos = it2.vpos; } else - xfree (it2data); + bidi_unshelve_cache (it2data, 1); } - bidi_unshelve_cache (itdata); + bidi_unshelve_cache (itdata, 0); if (old_buffer) set_buffer_internal_1 (old_buffer); @@ -2629,7 +2629,7 @@ init_iterator (struct it *it, struct window *w, it->paragraph_embedding = R2L; else it->paragraph_embedding = NEUTRAL_DIR; - bidi_unshelve_cache (NULL); + bidi_unshelve_cache (NULL, 0); bidi_init_it (charpos, IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f), &it->bidi_it); } @@ -5635,7 +5635,7 @@ back_to_previous_visible_line_start (struct it *it) pos = --IT_CHARPOS (it2); --IT_BYTEPOS (it2); it2.sp = 0; - bidi_unshelve_cache (NULL); + bidi_unshelve_cache (NULL, 0); it2.string_from_display_prop_p = 0; it2.from_disp_prop_p = 0; if (handle_display_prop (&it2) == HANDLED_RETURN @@ -5827,7 +5827,7 @@ reseat_1 (struct it *it, struct text_pos pos, int set_stop_p) { bidi_init_it (IT_CHARPOS (*it), IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f), &it->bidi_it); - bidi_unshelve_cache (NULL); + bidi_unshelve_cache (NULL, 0); it->bidi_it.paragraph_dir = NEUTRAL_DIR; it->bidi_it.string.s = NULL; it->bidi_it.string.lstring = Qnil; @@ -7995,13 +7995,13 @@ move_it_in_display_line_to (struct it *it, positions smaller than TO_CHARPOS, return MOVE_POS_MATCH_OR_ZV, like the unidirectional display did. */ - if ((op & MOVE_TO_POS) != 0 + if (it->bidi_p && (op & MOVE_TO_POS) != 0 && !saw_smaller_pos && IT_CHARPOS (*it) > to_charpos) { - result = MOVE_POS_MATCH_OR_ZV; - if (it->bidi_p && IT_CHARPOS (ppos_it) < ZV) + if (IT_CHARPOS (ppos_it) < ZV) RESTORE_IT (it, &ppos_it, ppos_data); + goto buffer_pos_reached; } else result = MOVE_NEWLINE_OR_CR; @@ -8040,14 +8040,13 @@ move_it_in_display_line_to (struct it *it, character positions smaller than TO_CHARPOS, return MOVE_POS_MATCH_OR_ZV, like the unidirectional display did. */ - || ((op & MOVE_TO_POS) != 0 + || (it->bidi_p && (op & MOVE_TO_POS) != 0 && !saw_smaller_pos && IT_CHARPOS (*it) > to_charpos)) { - result = MOVE_POS_MATCH_OR_ZV; - if (it->bidi_p && !at_eob_p && IT_CHARPOS (ppos_it) < ZV) + if (!at_eob_p && IT_CHARPOS (ppos_it) < ZV) RESTORE_IT (it, &ppos_it, ppos_data); - break; + goto buffer_pos_reached; } if (ITERATOR_AT_END_OF_LINE_P (it)) { @@ -8055,14 +8054,13 @@ move_it_in_display_line_to (struct it *it, break; } } - else if ((op & MOVE_TO_POS) != 0 + else if (it->bidi_p && (op & MOVE_TO_POS) != 0 && !saw_smaller_pos && IT_CHARPOS (*it) > to_charpos) { - result = MOVE_POS_MATCH_OR_ZV; - if (it->bidi_p && IT_CHARPOS (ppos_it) < ZV) + if (IT_CHARPOS (ppos_it) < ZV) RESTORE_IT (it, &ppos_it, ppos_data); - break; + goto buffer_pos_reached; } result = MOVE_LINE_TRUNCATED; break; @@ -8082,13 +8080,13 @@ move_it_in_display_line_to (struct it *it, done: if (atpos_data) - xfree (atpos_data); + bidi_unshelve_cache (atpos_data, 1); if (atx_data) - xfree (atx_data); + bidi_unshelve_cache (atx_data, 1); if (wrap_data) - xfree (wrap_data); + bidi_unshelve_cache (wrap_data, 1); if (ppos_data) - xfree (ppos_data); + bidi_unshelve_cache (ppos_data, 1); /* Restore the iterator settings altered at the beginning of this function. */ @@ -8123,7 +8121,7 @@ move_it_in_display_line (struct it *it, (it, -1, prev_x, MOVE_TO_X); } else - xfree (save_data); + bidi_unshelve_cache (save_data, 1); } else move_it_in_display_line_to (it, to_charpos, to_x, op); @@ -8382,7 +8380,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos } if (backup_data) - xfree (backup_data); + bidi_unshelve_cache (backup_data, 1); TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached)); } @@ -8461,7 +8459,7 @@ move_it_vertically_backward (struct it *it, int dy) RESTORE_IT (it, it, it2data); if (nlines > 0) move_it_by_lines (it, nlines); - xfree (it3data); + bidi_unshelve_cache (it3data, 1); } else { @@ -8657,7 +8655,7 @@ move_it_by_lines (struct it *it, int dvpos) if (IT_CHARPOS (*it) >= start_charpos) RESTORE_IT (it, &it2, it2data); else - xfree (it2data); + bidi_unshelve_cache (it2data, 1); } else RESTORE_IT (it, it, it2data); @@ -18764,6 +18762,9 @@ display_line (struct it *it) } } + if (wrap_data) + bidi_unshelve_cache (wrap_data, 1); + /* If line is not empty and hscrolled, maybe insert truncation glyphs at the left window margin. */ if (it->first_visible_x -- 2.11.4.GIT