diff options
author | Eric Blake <ebb9@byu.net> | 2008-07-14 16:26:12 -0600 |
---|---|---|
committer | Eric Blake <ebb9@byu.net> | 2009-04-17 07:05:16 -0600 |
commit | 5579e6f56cf88f840b926b563dab0361f2e2f502 (patch) | |
tree | 0839d6cd22470e3ca0fcdddc48d67f26982129f3 | |
parent | a404a0e157c3cccff9e2cc49df29f5e192e1af66 (diff) | |
download | m4-5579e6f56cf88f840b926b563dab0361f2e2f502.tar.gz |
Stage32: avoid copying text from defn
-rw-r--r-- | doc/m4.texinfo | 17 | ||||
-rw-r--r-- | src/input.c | 97 | ||||
-rw-r--r-- | src/m4.h | 1 | ||||
-rw-r--r-- | src/macro.c | 19 |
4 files changed, 116 insertions, 18 deletions
diff --git a/doc/m4.texinfo b/doc/m4.texinfo index 5b57222b..dc8c67ca 100644 --- a/doc/m4.texinfo +++ b/doc/m4.texinfo @@ -2346,6 +2346,23 @@ ifdef(`foo', `yes', `no') @result{}yes @end example +@ignore +@comment Stress test of defn, not worth putting in the manual. + +@example +define(`s', `0')define(`l', `0123456789012346789')define(`e', `$@@') +@result{} +e(defn(`s'), defn(`s', `s')defn(`s')) +@result{}0,000 +e(defn(`l'), ` +'defn(`l', `l')defn(`l')) +@result{}0123456789012346789, +@result{}012345678901234678901234567890123467890123456789012346789 +e(defn(`l', `s'), defn(`s', `l')) +@result{}01234567890123467890,00123456789012346789 +@end example +@end ignore + @node Pushdef @section Temporarily redefining macros diff --git a/src/input.c b/src/input.c index aaad0d7f..eafe95f1 100644 --- a/src/input.c +++ b/src/input.c @@ -239,6 +239,7 @@ make_text_link (struct obstack *obs, token_chain **start, token_chain **end) chain->u.u_s.str = str; chain->u.u_s.len = len; chain->u.u_s.level = -1; + chain->u.u_s.sym = NULL; } } @@ -359,6 +360,7 @@ push_string_init (const char *file, int line) void push_defn (symbol *sym) { + token_chain *chain; size_t len = SYMBOL_TEXT_LEN (sym); assert (next && SYMBOL_TYPE (sym) == TOKEN_TEXT); @@ -379,11 +381,20 @@ push_defn (symbol *sym) } make_text_link (current_input, &next->u.u_c.chain, &next->u.u_c.end); - /* TODO - optimize this to increment the symbol's reference counter, - then decrement it again upon rescan, rather than copying. */ - obstack_grow (current_input, SYMBOL_TEXT (sym), len); - make_text_link (current_input, &next->u.u_c.chain, &next->u.u_c.end); - next->u.u_c.end->quote_age = SYMBOL_TEXT_QUOTE_AGE (sym); + chain = (token_chain *) obstack_alloc (current_input, sizeof *chain); + if (next->u.u_c.end) + next->u.u_c.end->next = chain; + else + next->u.u_c.chain = chain; + next->u.u_c.end = chain; + chain->next = NULL; + chain->type = CHAIN_STR; + chain->quote_age = SYMBOL_TEXT_QUOTE_AGE (sym); + chain->u.u_s.str = SYMBOL_TEXT (sym); + chain->u.u_s.len = len; + chain->u.u_s.level = -1; + chain->u.u_s.sym = sym; + SYMBOL_PENDING_EXPANSIONS (sym)++; } /*--------------------------------------------------------------------. @@ -486,6 +497,7 @@ push_token (token_data *token, int level, bool inuse) chain->u.u_s.str = TOKEN_DATA_TEXT (token); chain->u.u_s.len = TOKEN_DATA_LEN (token); chain->u.u_s.level = level; + chain->u.u_s.sym = NULL; adjust_refcount (level, true); inuse = true; } @@ -498,7 +510,8 @@ push_token (token_data *token, int level, bool inuse) src_chain = src_chain->next; continue; } - if (level == -1) + if (level == -1 + && (src_chain->type != CHAIN_STR || !src_chain->u.u_s.sym)) { /* Nothing to copy, since link already lives on obstack. */ assert (src_chain->type != CHAIN_STR @@ -510,7 +523,8 @@ push_token (token_data *token, int level, bool inuse) /* Allow inlining the final link with subsequent text. */ if (!src_chain->next && src_chain->type == CHAIN_STR && (src_chain->u.u_s.len <= INPUT_INLINE_THRESHOLD - || (!inuse && src_chain->u.u_s.level == -1))) + || (!inuse && src_chain->u.u_s.level == -1 + && !src_chain->u.u_s.sym))) { obstack_grow (current_input, src_chain->u.u_s.str, src_chain->u.u_s.len); @@ -523,11 +537,12 @@ push_token (token_data *token, int level, bool inuse) chain->next = NULL; if (chain->type == CHAIN_STR && chain->u.u_s.level == -1) { - if (chain->u.u_s.len <= INPUT_INLINE_THRESHOLD || !inuse) + if (chain->u.u_s.len <= INPUT_INLINE_THRESHOLD + || (!inuse && !chain->u.u_s.sym)) chain->u.u_s.str = (char *) obstack_copy (current_input, chain->u.u_s.str, chain->u.u_s.len); - else + else if (!chain->u.u_s.sym) { chain->u.u_s.level = level; inuse = true; @@ -544,8 +559,16 @@ push_token (token_data *token, int level, bool inuse) assert (!chain->u.u_a.comma && !chain->u.u_a.skip_last); inuse |= arg_adjust_refcount (chain->u.u_a.argv, true); } - else if (chain->type == CHAIN_STR && chain->u.u_s.level >= 0) - adjust_refcount (chain->u.u_s.level, true); + else if (chain->type == CHAIN_STR) + { + if (chain->u.u_s.level >= 0) + { + assert (!chain->u.u_s.sym); + adjust_refcount (chain->u.u_s.level, true); + } + else if (chain->u.u_s.sym) + SYMBOL_PENDING_EXPANSIONS (chain->u.u_s.sym)++; + } src_chain = src_chain->next; } return inuse; @@ -612,6 +635,7 @@ push_quote_wrapper (void) curr_quote.len1); chain->u.u_s.len = curr_quote.len1; chain->u.u_s.level = -1; + chain->u.u_s.sym = NULL; } } @@ -745,7 +769,17 @@ pop_input (bool cleanup) if (chain->u.u_s.len) return false; if (chain->u.u_s.level >= 0) - adjust_refcount (chain->u.u_s.level, false); + { + assert (!chain->u.u_s.sym); + adjust_refcount (chain->u.u_s.level, false); + } + else if (chain->u.u_s.sym) + { + assert (SYMBOL_PENDING_EXPANSIONS (chain->u.u_s.sym)); + --SYMBOL_PENDING_EXPANSIONS (chain->u.u_s.sym); + if (SYMBOL_DELETED (chain->u.u_s.sym)) + free_symbol (chain->u.u_s.sym); + } break; case CHAIN_FUNC: if (chain->u.func) @@ -1015,7 +1049,17 @@ next_buffer (size_t *len, bool allow_quote) return chain->u.u_s.str; } if (chain->u.u_s.level >= 0) - adjust_refcount (chain->u.u_s.level, false); + { + assert (!chain->u.u_s.sym); + adjust_refcount (chain->u.u_s.level, false); + } + else if (chain->u.u_s.sym) + { + assert (SYMBOL_PENDING_EXPANSIONS (chain->u.u_s.sym)); + --SYMBOL_PENDING_EXPANSIONS (chain->u.u_s.sym); + if (SYMBOL_DELETED (chain->u.u_s.sym)) + free_symbol (chain->u.u_s.sym); + } break; case CHAIN_FUNC: if (chain->u.func) @@ -1342,7 +1386,17 @@ next_char_1 (bool allow_quote, bool allow_argv) return to_uchar (*chain->u.u_s.str++); } if (chain->u.u_s.level >= 0) - adjust_refcount (chain->u.u_s.level, false); + { + assert (!chain->u.u_s.sym); + adjust_refcount (chain->u.u_s.level, false); + } + else if (chain->u.u_s.sym) + { + assert (SYMBOL_PENDING_EXPANSIONS (chain->u.u_s.sym)); + --SYMBOL_PENDING_EXPANSIONS (chain->u.u_s.sym); + if (SYMBOL_DELETED (chain->u.u_s.sym)) + free_symbol (chain->u.u_s.sym); + } break; case CHAIN_FUNC: if (chain->u.func) @@ -1505,12 +1559,21 @@ append_quote_token (struct obstack *obs, token_data *td) time to inline the token text. Also, if the quoted string does not live in a back-reference, it must be copied. */ if (src_chain->type == CHAIN_STR - && (src_chain->u.u_s.len <= INPUT_INLINE_THRESHOLD - || src_chain->u.u_s.level < 0)) + && src_chain->u.u_s.len <= INPUT_INLINE_THRESHOLD) { obstack_grow (obs, src_chain->u.u_s.str, src_chain->u.u_s.len); if (src_chain->u.u_s.level >= 0) - adjust_refcount (src_chain->u.u_s.level, false); + { + assert (!src_chain->u.u_s.sym); + adjust_refcount (src_chain->u.u_s.level, false); + } + else if (src_chain->u.u_s.sym) + { + assert (SYMBOL_PENDING_EXPANSIONS (src_chain->u.u_s.sym)); + --SYMBOL_PENDING_EXPANSIONS (src_chain->u.u_s.sym); + if (SYMBOL_DELETED (src_chain->u.u_s.sym)) + free_symbol (src_chain->u.u_s.sym); + } return; } @@ -263,6 +263,7 @@ struct token_chain const char *str; /* Pointer to text. */ size_t len; /* Remaining length of str. */ int level; /* Expansion level of link content, or -1. */ + symbol *sym; /* Symbol that owns str, or NULL. */ } u_s; builtin_func *func; /* Builtin token from defn. */ diff --git a/src/macro.c b/src/macro.c index f565f5e5..5eab10f1 100644 --- a/src/macro.c +++ b/src/macro.c @@ -680,6 +680,7 @@ expand_macro (symbol *sym) /* Cleanup. */ argv->info = NULL; --expansion_level; + assert (SYMBOL_PENDING_EXPANSIONS (sym)); --SYMBOL_PENDING_EXPANSIONS (sym); if (SYMBOL_DELETED (sym)) @@ -760,7 +761,23 @@ arg_adjust_refcount (macro_arguments *argv, bool increase) { case CHAIN_STR: if (chain->u.u_s.level >= 0) - adjust_refcount (chain->u.u_s.level, increase); + { + assert (!chain->u.u_s.sym); + adjust_refcount (chain->u.u_s.level, increase); + } + else if (chain->u.u_s.sym) + { + symbol *sym = chain->u.u_s.sym; + if (increase) + SYMBOL_PENDING_EXPANSIONS (sym)++; + else + { + assert (SYMBOL_PENDING_EXPANSIONS (sym)); + --SYMBOL_PENDING_EXPANSIONS (sym); + if (SYMBOL_DELETED (sym)) + free_symbol (sym); + } + } break; case CHAIN_FUNC: break; |